当C++程序崩溃时如何获取堆栈跟踪?(使用msvc8 / 2005)

8
有时候我的 C++ 程序在调试模式下会崩溃,我收到的是一个消息框,上面显示了一条信息,说在一些内存管理例程(访问未分配的内存等)中断言失败。但我不知道它是从哪里被调用的,因为我没有得到任何堆栈跟踪信息。如何获取堆栈跟踪信息或者至少看到它在我的代码中失败的位置(而不是库/内置例程中)?

本文介绍如何计算堆栈跟踪。该文章 - Xavier Nodet
7个回答

7
如果您遇到了崩溃,无论是debug还是release版本,都可以获取关于崩溃发生位置的信息。即使您在没有源代码的计算机上,也可以查看调用堆栈。
为此,您需要使用与EXE一起构建的PDB文件。将PDB文件放置在崩溃的EXE相同目录下。注意:即使您拥有相同的源代码,构建两次并使用第一个EXE和第二个PDB也不起作用。您需要使用与EXE一起构建的确切PDB文件。
然后将调试器附加到崩溃的进程上。例如:windbg或VS。
然后只需检查您的调用堆栈,同时也要打开线程窗口。您将需要选择崩溃的线程并检查该线程的调用堆栈。每个线程都有不同的调用堆栈。
如果您已经连接了VS调试器,则它会自动转到导致崩溃的源代码。
如果崩溃发生在您正在使用但没有PDB的库内部,则无能为力。

至少你可以看到哪个库函数调用导致了崩溃。 - Thomas
在VS的中间窗口中,您可以键入(如果您有WinDBG):“.load sos.dll”(不带引号),并使用SOS调试器。 - user7116

3
如果您在安装了VS的计算机上运行调试版本,它应该会提示您打开并查看堆栈跟踪。
问题是真正的问题不再出现在调用堆栈中。 如果您两次释放指针,则可能导致此问题出现在与程序无关的其他地方(下一次访问堆数据结构时)。
我写了这篇博客,介绍了一些提示,以便在调用堆栈中显示问题,以便您可以找出问题所在。

http://www.atalasoft.com/cs/blogs/loufranco/archive/2007/02/06/6-_2200_Pointers_2200_-on-Debugging-Unmanaged-Code.aspx

最好的建议是使用gflags实用程序,以使指针问题立即引起问题。

谢谢你提供关于gflags的信息,我之前并不知道它的存在。 - Brian R. Bondy
我有一种感觉,这个实用程序将来可以为我节省数月的工作 :) - Brian R. Bondy
当我遇到任何类型的内存崩溃时,我会立即使用页面堆特性 -- 这样可以节省很多时间。 - Lou Franco

3
你可以通过设置未捕获异常的处理程序来触发迷你转储。这里有一篇文章介绍了所有关于迷你转储的内容。
Google实际上实现了他们自己的开源崩溃处理程序BreakPad,我认为Mozilla也在使用(如果您需要更严肃、丰富和强大的崩溃处理程序)。

0

如果我没记错的话,那个消息框应该有一个按钮,上面写着“重试”。这样做会在断言发生的地方(在调试器中)中断程序。


0

CrashFinder 可以帮助您定位异常的位置,只需提供 DLL 和异常报告的地址即可。
您可以将此代码集成到您的应用程序中,以在出现未捕获的异常时自动生成堆栈跟踪。通常使用 __try{} __except{} 或调用 SetUnhandledExceptionFilter 来执行此操作,后者允许您指定所有未处理异常的回调函数。


0

你还可以在客户端系统上安装事后调试器。这是一个不错的通用方法,可以在应用程序没有崩溃转储功能时(也许是针对旧版本,你仍需获取信息)获取信息。

在Windows上,可以通过运行命令drwtsn32 -i安装Dr. Watson。 运行drwtsn32(不带任何选项)将显示配置对话框。这将允许创建崩溃转储文件,稍后可以使用WinDbg或类似工具进行分析。


-1
你可以使用Poppy来实现这个功能。你只需要在代码中添加一些宏,它就会收集堆栈跟踪信息,以及实际参数值、本地变量、循环计数器等。它非常轻量级,因此可以留在发布版本中,从最终用户的机器上收集崩溃信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接