调试难以找到的异常

Debugging hard-to-find exceptions

本文关键字:异常 调试      更新时间:2023-10-16

首先,感谢您花时间查看我的问题并提供帮助。我注意到这里的很多提问者几乎没有表示赞赏,但我真诚地感谢这里的帮助和社区:)

我为一个没有源代码的应用程序(这是一个视频游戏)写了一个C++插件(泄露了数百个源文件)。换句话说,我只有插件的源代码,但没有游戏。现在,在我的插件中的数千行中,有什么东西导致游戏引擎抛出(可能是访问违规),我不知道在哪里。调试器中断时,堆栈已损坏,我得到的只是没有源的DLL的十六进制地址(但异常肯定发生在我的DLL中)。我什么都试过了。。。我似乎就是找不到异常发生的地方。有时调试器指向一个"内存重定位"函数(我从未在插件中使用过),有时它指向引擎的GameFrame(),有时则指向损坏回调(所有这些都是类的不同成员函数)。

我几乎什么都试过了。。。我在谷歌上搜索了几个小时,试图找出如何使用其他调试器,如WinDbg和Microsoft应用程序验证程序。我试图注释掉调试器指向的一个或另一个,或两者,但它仍然崩溃。我甚至将OUTPUT("The name of the last executed function is: %s", __FUNCTION__)插入到我的应用程序中的每个函数中,希望能费力地捕获最后一个函数,但似乎任何类型的I/O都会出于某种原因阻止异常的发生。。。经过10分钟的调试,崩溃发生在最后一个随机执行的函数上。

我找不到这种访问违规发生在哪里,也找不到一些临时对象在哪里被删除以导致这些坏指针(我在使用它之前会检查每个指针),但该死的,我已经达到了极限。

那么,如何调试不可能的。。。一个糟糕的调试器调用堆栈随机崩溃?提前感谢您的耐心和善意帮助!

我的建议:尝试不同的调试器(非MS),它们会捕获不同的东西。我的经验:我有一个程序的源代码和完整的调试符号破坏了堆栈,VS和WinDbg都可以帮助,但Ollydbg用值"r for pattern."注释了一个非字符串var,所以我已经在这个var上覆盖了一些字符串缓冲区。此外,Ollydbg可以选择艰难地遍历堆栈(不使用dbghelp.dll)

根据我的经验,"预防胜于治疗"这句古老的格言非常贴切。最好是通过遵循良好的软件开发实践(单元测试、回归、代码审查等)来防止错误悄悄出现,而不是在错误出现后再解决。

当然,现实世界并不是完美的,bug确实会出现。要调试内存损坏,你有一些不错的工具,比如valgrind,它至少缩小了问题的范围,让你仔细研究一下。调试一个复杂的程序并不容易,如果你的调试器出现问题,你需要大量的持久性。我发现一种有用的技术是选择性地启用或禁用某些模块,以缩小模块存在问题的范围。

有时您需要使用"引用透明度"来卸载一些模块。举个简单的例子,考虑一下:

int foo = factorial(3);

如果我怀疑这段代码中有问题(在我看到调用堆栈之前调试器就崩溃了),我必须尝试删除这段代码,看看问题是否仍然存在。但是foo可能会在以后使用,所以我不能直接删除它。相反,我可以用int foo = 6;替换它并继续。

另一个重要的点是始终维护一个跟踪文件,您的代码会在其中记录它正在做的事情。当程序崩溃时,跟踪文件通常可以帮助缩小问题范围。当然,默认情况下会禁用跟踪,这样就不会造成性能瓶颈。