我发现尝试在gdb中意外调试未初始化的数据可能很烦人。从命令行直接执行时程序将崩溃,但在gdb中检查时不会崩溃。看起来gdb的堆通常是干净的(全为零),而从命令行来看,显然不是。
这有什么理由吗?如果是这样,我可以故意告诉gdb或gcc弄脏堆吗? IE,有没有办法指定一个“调试”分配器,它总是会向malloc()
和new
提供随机数据?我想这可能涉及一个特殊的libc?显然,如果有一种方法可以在不更改链接器选项的情况下执行此操作,那么发布版本与调试版本尽可能相似。
我目前正在使用MinGW-w64(基于gcc 4.7),但我对一般答案感兴趣。
答案 0 :(得分:1)
Linux的做法是使用valgrind。在Mac OS X上,有一些控制分配调试的环境变量see the Mac OS X man page for malloc。 Valgrind对Mac OS X的支持已经开始出现,但是当我写这篇文章时,10.8支持还没有完成。
当你使用MinGW-w64我假设你正在使用Windows。似乎this SO question讨论了Windows上valgrind的替代方案。一种解决方案是在valgrind下的Linux机器上运行Wine中的应用程序。
如果您的程序在valgrind下运行,则它不会直接在CPU上运行。 Valgrind正在模拟每条指令,因此您不能简单地将调试器附加到它上面。要使其工作,您需要使用valgrind GDB服务器,有关详细信息,请参阅this page。
另一种方法是使用calloc
而不是malloc
,这将使您的堆分配归零。这不会给你一个故意脏的堆,但至少可以在有或没有调试器的情况下给你一致的行为。
答案 1 :(得分:0)
是的,GDB将所有内容归零,这既有用又非常烦人。有用,只要保证一切都处于明确定义的状态(内存中没有随机值,只有零)。从理论上讲,这意味着在调试时没有令人讨厌的意外
在实践中,这是令人讨厌的地方,理论有时会失败。臭名昭着的“工作正常,但是在调试器中崩溃了!?!”或“在调试器中工作正常,但是否则会崩溃?!”问题就是一个例子。通常情况下,这是一个未初始化的指针与某个意图良好的if(ptr != NULL)
的组合,由于调试器将内存初始化为零,所以测试无法按照您的意图进行操作,因此“完全没有理由”。
关于故意混淆由malloc
分配的数据的问题,GCC支持malloc挂钩(请参阅docs here和question here on SO)。
这使您能够以非常简单且不引人注目的方式将所有对malloc
的调用重定向到您自己的函数。从那里你可以调用真实的malloc
并用垃圾填充分配的块(或者像DEADBEEF
这样的无效指针魔术值),如果你愿意的话。
至于operator new
,这恰好是malloc
的包装(这是一个实现细节,但malloc挂钩已经不可移植了,所以依赖它不会让事情变得更糟),因此,malloc挂钩也应该已经解决了这个问题。