我只是花了一些时间来追逐一个归结为以下的错误.代码错误地覆盖了堆栈,我认为它写了函数调用的返回地址.返回后,程序将崩溃并且堆栈将被破坏.在valgrind中运行程序将返回错误,例如:
vex x86->IR: unhandled instruction bytes: 0xEA 0x3 0x0 0x0 ==9222== valgrind: Unrecognised instruction at address 0x4e925a8.
我认为这是因为返回跳转到一个随机位置,包含无效的x86操作码.(虽然我有点怀疑这个地址0x4e925a8恰好在一个可执行页面中.我想如果不是这样的话,valgrind会抛出一个不同的错误.)
我确定问题是堆栈覆盖类型,我已经修复了它.现在我正在努力思考如何更有效地捕捉这样的错误.显然,如果我在堆栈上重写数据,valgrind就不能警告我,但是当有人在堆栈上写入返回地址时,它可能会捕获.原则上,它可以检测何时发生'push EIP'(因此它可以标记返回地址在堆栈中的位置).
我想知道是否有人知道Valgrind或其他任何东西能否做到这一点?如果没有,您是否可以有效地评论有关此类调试错误的其他建议.
通常,Valgrind检测堆栈和全局变量中的溢出对于不存在是弱的.可以说,Valgrind是这项工作的错误工具.
如果您使用的是受支持的平台之一,那么构建-fmudflap
和链接-lmudflap
将为这些类型的错误提供更好的结果.其他文档在这里.
Udpdate:
自这个答案以来的6年里,情况发生了很大的变化.在Linux上,查找堆栈(和堆)溢出的工具是AddressSanitizer,由最新版本的GCC和Clang支持.
如果问题确定性地发生,你可以指出特定的功能,它的堆栈被粉碎(在一个可重复的测试用例中),你可以在gdb中:
在进入该功能时休息
找到存储返回地址的位置(它相对于%ebp
(在x86上)(它保留%esp
了函数入口的值),我不确定是否有任何偏移).
将观察点添加到该地址.您必须watch
使用计算出的数字而不是表达式发出命令,因为使用表达式gdb会尝试在每条指令后重新计算它而不是设置陷阱,这将非常慢.
让函数运行完成.
我还没有使用gdb7中提供的python支持,但它应该允许自动执行此操作.