3

我发现尝试在 gdb 中调试意外未初始化的数据可能很烦人。程序在命令行直接执行时会崩溃,但在 gdb 中检查时不会。看起来 gdb 的堆通常是干净的(全为零),而从命令行来看,显然不是。

是否有一个原因?如果是这样,我可以故意告诉 gdb 或 gcc 弄脏堆吗?IE,有没有办法指定一个“调试”分配器,它总是给malloc()和随机数据new?我想这可能涉及一个特殊的 libc?显然,如果有一种方法可以在不更改链接器选项的情况下做到这一点,那就太好了,这样发布版本就尽可能地与调试版本相似。

我目前正在使用 MinGW-w64(基于 gcc 4.7),但我会对一般答案感兴趣。

4

2 回答 2

1

这样做的 Linux 方法是使用 valgrind。在 Mac OS X 上,有控制分配调试的环境变量,请参阅 malloc 的 Mac OS X 手册页。Valgrind 对 Mac OS X 的支持开始出现,但在我写这篇文章时,10.8 的支持还不完整。

当您使用 MinGW-w64 时,我假设您使用的是 Windows。似乎这个 SO question谈到了 Windows 上 valgrind 的替代方案。一种解决方案是在 valgrind 下的 Linux 机器上的 Wine 中运行您的应用程序。

如果您的程序在 valgrind 下运行,则它不会直接在 CPU 上运行。Valgrind 正在模拟每条指令,因此您不能简单地将调试器附加到它。要使其工作,您需要使用 valgrind GDB 服务器,请参阅此页面了解更多详细信息。

另一种方法是使用calloc而不是malloc,这将使您的堆分配归零。这不会给你一个故意弄脏的堆,但至少可以让你在有或没有调试器的情况下保持一致的行为。

于 2013-03-18T16:25:43.553 回答
0

是的,GDB 将所有内容归零,这既有用又很烦人。有用,只要保证一切都处于明确定义的状态(内存中没有随机值,只有零)。这意味着,从理论上讲,调试时不会出现令人讨厌的意外。
在实践中,这就是令人讨厌的地方,这个理论有时会失败。臭名昭著的“工作正常,但在调试器中崩溃!?!” “在调试器中工作正常,但在其他情况下崩溃?!” 问题就是一个例子。通常,这是一个未初始化的指针与一个善意的if(ptr != NULL)地方的组合,这完全因为“没有充分的理由”而崩溃,因为调试器将内存初始化为零,因此测试无法达到您的预期。

关于您关于故意乱码分配的数据的问题malloc,GCC 支持 malloc 钩子(请参阅此处的文档有关 SO 的问题)。

这使您能够以一种非常简单且非侵入性的方式将所有调用重定向到malloc您自己的函数。如果您愿意,您可以从那里调用 realmalloc并用垃圾(或一些无效指针魔法值,如 )填充分配的块DEADBEEF

至于operator new,这恰好是一个包装器malloc(这是一个实现细节,但是 malloc 钩子已经是不可移植的,因此依赖它不会使事情变得更糟),因此 malloc 钩子也应该已经处理了这个问题。

于 2013-03-18T17:02:03.950 回答