2

编辑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,它在 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 funcs。

调试跟踪

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 行。由于 self->_garbage 已被完全释放,这应该是“双重释放或损坏”发生的地方。但是,整个函数是连续的,没有循环。我不明白为什么它跳回来了。

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

  • sp_env_list_free_children() 将所有 e->_data 从 e = self->_garbage->head 释放到 e = self->_garbage->tail。
  • sp_env_list_del ()删除从self->_garbage->head到self->_garbage->tail的指针
  • sp_env_free() 释放 self->_garbage 指针

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

4

1 回答 1

4

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

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

由于结语位于函数的末尾,它名义上的行号为 6857,即使该行上可见的所有内容都是右括号。所以 TCO 和你看到的行号顺序是完全一致的。不过,我敢肯定这不是唯一的可能性。一般来说,第二次猜测一个好的优化器并不容易。如果您真的想知道,您可以尝试使用 来查看生成的汇编代码-S,但鉴于您的文件至少有 6857 行,这可能也不容易破译。

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

于 2013-11-08T03:32:22.333 回答