我正在为一种小型计算机语言制作虚拟机。该虚拟机是使用 GNU 实用程序 Flex 用 C 语言开发的。因此,项目编译是使用 GNU GCC,然后是 Flex。
在这个虚拟机中,我有一个 GC Stop & Copy。在我更改之前,GC 的工作内存无法扩大 - 例如,如果第一次翻转没有优化用于进行新分配的空间,则从 512 字节变为 1024 字节。
这种改变似乎奏效了。事实上,我不知道自从这些更改后它是否真的有效,但现在我有一个错误。它刚刚出现在第一个翻转中。事实上,当涉及到复制数据时,我有一个不断变化的变量。但是这个变量很重要,因为它指向我要复制的项目。在 Stop & Copy 中,此变量用于更改插槽(此处SLOT_FORWARD
)以通知数据在内存中的新位置(以防我们仍然要复制)。
所以我有一个循环,它复制前一个容器的每个盒子,其在内存中的位置由变量指定old
。我有一个从addr
位置填充的新容器。但是旧值在迭代过程中发生了变化!并且在复制之后,我想将插槽向前更改以放置新容器的地址。但是随着 old 的变化,你可以想象我在错误的地方记录了这个值。
所以我花了很长时间调试这种情况很少发生的案例(它在 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 中运行 VM。很抱歉,我无法使代码更清晰。但问题只是神奇地出现了,我无法更进一步,制作出超越 Python 的未来语言(笑话)。
存储库的链接是: git.osau.re
更改的链接是:ompldr
亲切的问候。