8

我有一个客户遇到了 100% 可重现的崩溃,我无法在 Visual Studio 2005 中编译的程序中复制该崩溃。我向他们发送了我的程序的调试版本,并将所有 PDB 和 DLL 文件放在手边。他们向我发送了 minidump 文件,但是当我打开它时,我得到:

“MiniDump.dmp 中 0x00000000 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000。”

然后调用堆栈只显示“0x00000000()”,反汇编显示0x0处的内存转储。我已经设置了符号服务器,加载了我的 PDB 符号等。但是我看不出有任何方法可以知道许多 DLL 中的哪一个实际上导致了跳转到 null。这是一个具有许多依赖项的大型项目,其中一些是我没有源或 PDB 的二进制文件,因为我使用 API 作为第 3 方。

那么这个小型转储到底有什么用呢?如何查看导致崩溃的 DLL?我以前从未真正使用 minidump 进行调试,但我读过的所有教程似乎至少显示了一个函数名称或其他可以在调用堆栈中为您提供线索的内容。我只是得到指向空值的一行。

我还尝试使用“Depends”来查看是否存在一些未解决的 DLL 依赖项;但是在我的三台装有各种 Windows 操作系统的测试机器上,我似乎得到了三组不同的操作系统 DLL 依赖项(但无法复制崩溃);所以这似乎也不是诊断问题的特别可靠的方法。

还有哪些其他方法可以确定此问题的原因?有什么方法可以退回一条指令以查看哪个 DLL 跳转到空值?

4

6 回答 6

5

好吧,这个实例中的答案似乎是“使用 WinDbg 而不是 Visual Studio 来调试小型转储”。我无法从 VS 中获得任何有用的信息,但 WinDbg 为我提供了有关导致崩溃的函数调用链的大量信息。

在这种情况下,它仍然无助于解决我的问题,因为所有函数都在我正在使用的第 3 方库中,所以看起来对我的具体问题的唯一明确答案是使用日志文件来跟踪状态我的应用程序导致崩溃。

我想如果其他人在调试小型转储时看到类似的调用堆栈无用的问题,最好的做法是使用 WinDgb 而不是 Visual Studio 打开它。似乎很奇怪,这项工作的最佳工具是免费的 Microsoft 产品,而不是商业产品。

这里的另一个教训可能是“任何使用第三方库的程序都需要编写日志文件”。

于 2010-03-03T05:54:13.297 回答
2

所有“简单”的事后调试方法背后的整个想法是捕获堆栈跟踪。如果您的应用程序覆盖堆栈,则无法进行此类分析。只有在专用硬件中记录整个程序执行的非常复杂的方法才能有所帮助。

在这种情况下要走的路是日志文件。在发生故障的区域周围非常广泛地传播一些日志语句,并将该版本传输给客户。崩溃后,您将在日志文件中看到最后一条日志语句。在该点和未记录在日志文件中的下一个日志语句之间添加更多日志语句,再次发布该版本。重复直到找到导致问题的行。

我在 ddj.com 上写了一篇关于此的两部分文章:

关于日志文件第 1 部分

关于日志文件第 2 部分

于 2010-03-02T10:44:27.047 回答
0

只是一个观察,但堆栈被截断或覆盖,这可能是使用未初始化字段的简单情况,还是缓冲区溢出?

这可能很容易找到。

于 2010-03-02T10:46:43.907 回答
0

您是否尝试在客户的计算机上设置 WinDbg 并将其用作任何导致崩溃的应用程序的默认调试器?您只需要将 pdb 文件添加到应用程序所在的文件夹中。当暗恋发生时,WinDbg 启动,您可以尝试获取调用堆栈。

于 2010-03-02T14:01:43.333 回答
0

可能您已经知道这一点,但这里有一些关于 minidump 调试的要点: 1. 您需要拥有与创建 minidump 的客户端计算机完全相同的可执行文件和 PDB 文件,并且它们应该完全放在相同的目录中。只是重建相同的版本并没有帮助。2. 调试器必须连接到 MS Symbols 服务器。3. 当调试器启动时,它会在输出窗口中打印进程加载日志。通常,所有库都应成功加载调试信息。没有调试信息的库也会被加载,但会打印“无调试信息”。学习这个日志——它可以给你一些信息。

如果可执行堆栈包含来自没有调试信息的库的帧,则可能不会显示。例如,如果您的代码作为第三方库回调运行,就会发生这种情况。

尝试通过添加一些创建未处理异常的代码在您自己的计算机上创建小型转储,并立即对其进行调试。这行得通吗?比较成功和不成功调试会话中的加载日志。

于 2010-03-02T14:23:10.693 回答
0

您可能已经调用了空函数指针。需要当前执行的函数信息来显示调用堆栈信息。强制设置指令指针以启动任何简单函数,然后您将再次看到调用堆栈信息。

void SimpleFunc()
{  // <- set next statement here
} 
于 2016-06-21T08:14:23.030 回答