顺序代码执行中的有趣行为

时间:2013-11-07 23:06:00

标签: c debugging gdb

编辑2:我仍然被困在这里,但问题很可能出现在自动矢量化重写系统中,这与此问题无关。我将在下面的评论中提到的valgrind的SIGILL输出上再次更新这个问题

==10478== Process terminating with default action of signal 4 (SIGILL) 
==10478== Illegal opcode at address 0x423F4C ==10478== at 0x423F4C: sp_private_9_compute (smmintrin.h:209) 
==10478== by 0x4247F4: sp_private_9__timeCompute 

在调试SSE代码时,检查是否看到由valgrind引发的SIGILL的第一件事是你的VALGRIND是最新的在我的情况下,我使用的是V3.6,它有bug SSE4内在支持。 SIGILL被提出b / c它不理解_mm_mullo_epi32指令。将其更新到V3.9后,valgrind可以更好地找到SSE程序的真正问题。

如果我找到更相关的调试提示,我会再次更新此问题。


编辑1:我希望有人可以确认我对调试跟踪中非顺序行为的观察是准确的。


首先,这是一个关于C调试的非常具体的问题。如果您阅读并提供任何反馈,我真的很感激。

背景:我正在使用代码生成系统,最近我不断从glibc获得“双重免费或损坏”。因此,我使用额外的调试信息重新编译了自动生成的代码,并使用 gdb 运行它。而且我现在脑子已经死了,或者我实际上在顺序代码执行中观察到非连续行为

代码

LINE:6851     if(self->_garbage != 0) {
LINE:6852            sp_env_list_free_children(self->_garbage);
LINE:6853            sp_env_list___del__(self->_garbage);
LINE:6854            sp_env_free(self->_garbage, sizeof(sp_env_list_t));
LINE:6855     }//End of if
LINE:6856   }//End of an outer if structure
LINE:6857 }//End of the function call containing the if structure

我将在调试跟踪之后解释free和del func。

调试跟踪

6851   if (((self->_garbage != 0))) {
(gdb) step
6852   sp_env_list_free_children(self->_garbage);
(gdb) print self->_garbage 
$1 = (sp_env_list_t *) 0x649080
(gdb) step
6853   sp_env_list___del__(self->_garbage); 
(gdb) print self->_garbage 
$2 = (sp_env_list_t *) 0x649080
(gdb) step
6854      sp_env_free(self->_garbage, sizeof(sp_env_list_t )); 
(gdb) print self->_garbage 
$3 = (sp_env_list_t *) 0x649080
(gdb) step
6857   }
(gdb) print self->_garbage 
$4 = (sp_env_list_t *) 0x649080
(gdb) step
sp_private_11___del__ (self=<value optimized out>) at sp_moddft_int32.c:6854
6854      sp_env_free(self->_garbage, sizeof(sp_env_list_t )); 
(gdb) print self->_garbage 
Cannot access memory at address 0x18
(gdb) step
Single stepping until exit from function sp_env_free, 
which has no line number information.
*__GI___libc_free (mem=0x649080) at malloc.c:3692
3692    malloc.c: No such file or directory.
    in malloc.c

正如您在调试跟踪中看到的那样,它在第6854行之后到达第6857行,然后再次返回到第6854行。由于自我&gt; _garbage已经完全释放,这应该是“ double free or corruption ”发生的地方。但是,整个函数是顺序的,没有循环。我不明白为什么它会跳回来。

为了问题的完整性,if结构中的三个函数用于:

  • sp_env_list_free_children()将所有e-&gt; _data从e = self-&gt; _garbage-&gt;释放到e = self-&gt; _garbage-&gt;尾部。
  • sp_env_list_ del ()从self-&gt; _garbage-&gt;删除指向head to self-&gt; _garbage-&gt; tail
  • sp_env_free()释放self-&gt; _garbage指针

如果不清楚,我可以提供任何其他信息。我希望有人至少可以证实我对非连续行为的观察是准确的。非常感谢!

1 个答案:

答案 0 :(得分:4)

当您单步执行时,优化代码通常会随机跳转。只要维护定义的排序关系,优化器就可以自由地重新组织代码流。

在这种情况下,我怀疑你看到尾调用优化(TCO)的结果。您对sp_env_free的最后一次调用是尾调用,假设它所在的函数返回void。因此,函数可以恢复其被调用者保存寄存器(即执行结尾),然后跳转到sp_env_free,而不是调用sp_env_free然后执行结尾。这样可以节省堆栈帧和一些指令来设置堆栈帧。

由于结尾位于函数的末尾,因此它名义上具有行号6857,即使在该行上可见的所有内容都是紧密支撑。因此,TCO与您看到的行号序列完全一致。不过,我确信这不是唯一的可能性。一般来说,想要一个好的优化器并不容易;如果您真的想知道,可以尝试使用-S查看生成的汇编程序代码,但鉴于您的文件至少有6857行,这可能也不容易解密。

如果您想合理地调试程序,请关闭优化。