如何使用Valgrind调试堆栈覆盖错误?

时间:2011-04-28 03:57:21

标签: stack-overflow valgrind

我只是花了一些时间追逐一个归结为以下的错误。代码错误地覆盖了堆栈,我认为它写了函数调用的返回地址。返回后,程序将崩溃并且堆栈将被破坏。在valgrind中运行程序将返回错误,例如:

vex x86->IR: unhandled instruction bytes: 0xEA 0x3 0x0 0x0
==9222== valgrind: Unrecognised instruction at address 0x4e925a8.

我认为这是因为返回跳转到一个随机位置,包含无效的x86操作码。 (虽然我有点怀疑这个地址0x4e925a8恰好在一个可执行页面中。我想如果不是这样的话,valgrind会抛出一个不同的错误。)

我确定问题是堆栈覆盖类型,我已经修复了它。现在我正在努力思考如何更有效地捕捉这样的错误。显然,如果我在堆栈上重写 data ,valgrind就无法警告我,但是当有人在堆栈上写入返回地址时,它可能会捕获。原则上,它可以检测何时发生'push EIP'(因此它可以标记返回地址在堆栈中的位置)。

我想知道是否有人知道Valgrind或其他任何东西能否做到这一点?如果没有,您是否可以有效地评论有关此类调试错误的其他建议。

2 个答案:

答案 0 :(得分:6)

通常,Valgrind检测堆栈和全局变量中的溢出对于不存在是弱的。可以说,Valgrind是这项工作的错误工具。

如果您使用的是受支持的平台之一,使用-fmudflap构建并与-lmudflap建立链接可以为这些类型的错误提供更好的结果。其他文档here

<强> Udpdate:

自这个答案以来的6年里,情况发生了很大的变化。在Linux上,找到堆栈(和堆)溢出的 工具是AddressSanitizer,由最新版本的GCC和Clang支持。

答案 1 :(得分:5)

如果问题确定性地发生,你可以指出特定的功能,它的堆栈被粉碎(在一个可重复的测试用例中),你可以在gdb:

  1. 在进入该职能时休息
  2. 找到存储返回地址的位置(它相对于%ebp(在x86上)(它将%esp的值保留在函数入口处),我不确定是否有任何偏移量)
  3. 将观察点添加到该地址。您必须使用计算出的数字而不是表达式发出watch命令,因为使用表达式gdb将尝试在每条指令后重新计算它而不是设置陷阱,这将非常慢。
  4. 让功能运行完成。
  5. 我还没有使用gdb7中提供的python支持,但它应该允许自动执行此操作。