2

Я создаю виртуальную машину для небольшого компьютерного языка. Эта виртуальная машина разработана на C с помощью утилиты GNU Flex. Поэтому компиляция проекта с GNU GCC, а затем Flex.Как решить странное изменение значения?

Внутри этой виртуальной машины у меня есть остановка GC & Копия. До моих изменений рабочая память GC не могла быть увеличена - например, от 512 байт до 1024 байт, если первый флип не оптимизировал пространство, используемое для создания нового распределения.

Эти изменения, казалось, сработали. На самом деле, я не знаю, действительно ли это сработало с тех изменений, но теперь у меня есть ошибка. Он появился только в первом перевороте. Действительно, когда наступает копирование данных, У меня есть постоянная , которая меняет. Но эта переменная важна, потому что она указывает на элемент, который я хочу скопировать. В Stop & Copy эта переменная используется для изменения слота (здесь SLOT_FORWARD), чтобы сообщить новую позицию данных в памяти (в случае, если мы все равно скопируем).

Итак, у меня есть цикл, который копирует каждый ящик предыдущего контейнера, положение которого в памяти задается переменной old. И у меня есть новый контейнер, который заполняется с позиции addr. Но старое значение изменяется во время итерации! И после копии я хочу изменить слот вперед, чтобы поместить новый адрес контейнера. Но по мере того как старый изменился, вы можете себе представить, что я записываю это значение не в том месте.

Так что я долгое время отлаживал случаи, когда это случается очень редко (это случается несколько раз после 2 переворота с 3 по 4 контейнера). Я использую GDB, чтобы знать значение, измененное в одной из моих функций отладки (в то время как она также была изменена добавлением функций отладки). Затем я сменил компилятор (clang на gcc), чтобы перезапустить GDB и увидеть, что это был символ привязки (все еще в функции отладки), который изменил значение ... Наконец, я поместил все свои параметры для всех функций const, когда это было возможно, и теперь мне говорят, что значение было изменено в файле iofwrite.c строка 37. Это, следовательно, ошибка из другого мира.

Код в вопросе, где ошибка здесь:

static t_case 
copy(t_dono *dono, const t_case old) 
{ 
    t_case addr; 
    t_case size; 
    t_case temp; 
    int  i; 

    temp = old; 

    if (mem[old + SLOT_FORWARD] >= ns 
     && mem[old + SLOT_FORWARD] <= ts) 
    return (mem[old + SLOT_FORWARD]); 
    else 
    { 
     addr = mp; 
     size = mem[old + SLOT_SIZE]; 
     i = 0; 

     fprintf(stderr, "change:\t"); 
     dump(stderr, mem, old); 

     assert(old == temp); 

     while (i < size) 
     { 
      fprintf(stderr, "!!!COPY:\t"); 
      dump(stderr, mem, old); 
      assert(old == temp); 
      mem[addr + i] = mem[old + i]; /* BUG IS HERE */ 
      i = i + 1; 
     } 

     mem[old + SLOT_FORWARD] = addr; 
     fprintf(stderr, "change:\t"); 
     dump(stderr, mem, old); 
     assert(old == temp); 
     mp = mp + size; 

     return (addr); 
    } 
} 

Как вы можете видеть, что я сделал много отладки для нацеливания ошибки, и я получил этот файл журнала:

ref:   [ 0005 0001 0003 0004 0035 ] 
copy:   [ 0007 0001 0003 0004 0075 0001 00f9 ] 
change:   [ 0007 0001 0003 0004 0075 0001 00f9 ] 
!!!COPY:  [ 0007 0001 0003 0004 0075 0001 00f9 ] 
!!!COPY:  [ 0007 0001 0003 0004 0075 0001 00f9 ] 
!!!COPY:  [ 0007 0001 0003 0004 0075 0001 00f9 ] 
!!!COPY:  [ 0003 0001 0003 ] 
!!!COPY:  [ 0003 0004 0003 ] 
!!!COPY:  [ 0003 0004 0075 ] 
!!!COPY:  [ 0003 0004 0075 ] 
change:   [ 0003 0033 0075 ] 

Я также использовал Valgrind, который сказал мне, что много ошибок, но только после этой ошибки (что нормально, так как GC теперь будет получать доступ к случайным данным). Во время этой замены переменной у меня нет абсолютно никаких ошибок.

Мы можем видеть, что другие контейнеры, проходящие через функцию copy (l: 662), не получают этого неопределенного поведения (см. Файл журнала в строках 10, 48, 54, 66, 82, 120, 126 и 134). Только во время выполнения все идет не так, что, конечно, ошибочно все данные GC.

Код действительно длинный (около 1000 строк), поскольку цель состоит в том, чтобы запустить виртуальную машину в одном файле C. Мне жаль, что я не могу сделать код более понятным. Но проблема просто волшебная, и я не могу идти дальше и сделать язык будущего, который будет превосходить Python (шутка).

Ссылка на репозиторий: ссылка git.osau.re
Изменение заключается в следующем: ompldr

С наилучшими пожеланиями.

ответ

3

Отслеживание случайных кубиков памяти (это то, что это звучит) очень сложно. Моим подходом для этого было бы выяснить, когда компилятор решил поместить переменную изменения (возможно, где-то в стек), а затем установить точку наблюдения для этого местоположения. Это должно указывать вам, где код изменяет значение - вы, скорее всего, найдете его в некоторой вызываемой функции, которая выполняет резервное копирование стека, чтобы сделать шаг на вашей переменной. Тогда вам нужно выяснить, почему это происходит.

 Смежные вопросы

  • Нет связанных вопросов^_^