Я создаю виртуальную машину для небольшого компьютерного языка. Эта виртуальная машина разработана на 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
С наилучшими пожеланиями.