我正在写一个函数来计算给定的线性不等式系统是否有解,突然,在一个看似无害的改变之后,它开始给出错误的答案。
我撤销了一些修改,重做了一遍,然后在接下来的两个小时里继续拉小提琴,直到我把它简化为荒谬的样子。
下面的代码插入到函数体中的任何位置,但不在程序中的其他位置,可以修复它:
if(0) {
__asm__("nop\n");
__asm__("nop\n");
__asm__("nop\n");
__asm__("nop\n");
}这是一个学校作业,所以我可能不应该把这个函数发布在网络上,但这太荒谬了,我认为任何上下文都不会对你有所帮助。这个函数所做的就是一堆数学运算和循环。它甚至不会触及未在堆栈上分配的内存。
请帮助我理解这个世界!我不愿意把它归咎于GCC,因为调试的第一条规则是不能责怪编译器。不过,见鬼,我马上就要这么做了。我在G5平台上运行MacOS10.5,有问题的编译器自称是“powerpc-apple-darwin9- could 4.0.1”,但我认为它可能是个冒牌货……
更新:越来越好奇……我比较了有nops和没有nops的.s文件。不仅有太多的差异需要检查,而且在没有nops的情况下,.s文件是196,620字节,没有nops的情况下是156,719字节。(!)
更新2:哇,应该已经发布了代码!今天,我以全新的眼光回到代码中,立即看到了错误。请看下面我的害羞的自我回答。
发布于 2009-04-07 15:35:46
在忙于其他事情几天后,我又回到了这个问题上,并立即弄清楚了。抱歉,我没有早点发布代码,但是很难找出显示问题的最小示例。
根本问题是我在递归函数中遗漏了return语句。我有:
bool function() {
/* lots of code */
function()
}当它本应该是:
bool function() {
/* lots of code */
return function()
}这是因为,通过优化的魔力,正确的值恰好在正确的时间出现在正确的寄存器中,并将其放到了正确的位置。
这个bug最初是在我将第一个调用中断到它自己的特殊大小写函数中时引入的。在这一点上,额外的nops就是第一种情况直接内联到一般递归函数中的区别。
然后,由于我不完全理解的原因,内联第一种情况导致正确的值在正确的时间没有出现在正确的位置,函数返回垃圾。
发布于 2009-04-02 04:58:17
大多数情况下,当您不合理地修改代码并修复问题时,这是某种类型的内存损坏问题。我们可能需要看到实际的代码来进行适当的分析,但这将是我的第一个猜测,基于可用的信息。
发布于 2009-04-02 05:25:41
这是错误的指针算法,直接(通过指针)或间接(通过超过数组的末尾)。检查您的所有阵列。不要忘记,如果您的数组是
int a[4];那么a4就不存在了。
您所做的就是意外地覆盖了堆栈上的某些内容。堆栈包含本地变量、参数和函数的返回地址。您可能会以额外的noops修复的方式损坏返回地址。
例如,如果您有一些向返回地址添加内容的代码,插入额外的16字节的noops就可以解决这个问题,因为您不是返回到下一行代码,而是返回到某些noops的中间。
向返回地址添加内容的一种方法是越过局部数组或参数的末尾,例如
int a[4];
a[4]++;https://stackoverflow.com/questions/708339
复制相似问题