Heisenbug:WinApi程序在某些计算机上崩溃

时间:2008-09-25 08:27:41

标签: c++ debugging winapi crash gdi

请帮忙!我真的很有智慧。 我的程序是一个小个人笔记管理器(google为“cintanotes”)。 在某些计算机上(当然我没有它们),它在启动后就会出现未处理的异常。 除了他们倾向于使用AMD CPU之外,没有什么特别的关于这些计算机。

环境:Windows XP,Visual C ++ 2005/2008,原始WinApi。

以下是关于这个“Heisenbug”的确定内容:

1)崩溃只发生在Release版本中。

2)一旦删除所有与GDI相关的内容,崩溃就会消失。

3)BoundChecker没有抱怨。

4)编写日志表明崩溃发生在本地int变量的声明中!怎么会这样?内存损坏?

任何想法都将不胜感激!

更新:我设法在“有故障”的PC上调试了应用程序。结果:

“CintaNotes.exe中0x0044a26a处的未处理异常:0xC000001D:非法指令。”

上的代码中断

0044A26A cvtsi2sd xmm1,dword ptr [esp + 14h]

所以似乎问题出现在“代码生成/启用增强指令集”编译器选项中。它设置为“/ arch:SSE2”并且在不支持SSE2的计算机上崩溃。我已将此选项设置为“未设置”,并且错误消失了。呼<!/强>

非常感谢你们的帮助!!

11 个答案:

答案 0 :(得分:10)

  4)写一个日志表明崩溃发生在一个本地int变量的声明上!怎么会这样?内存损坏?

可执行文件/程序集中的底层代码是什么?声明int根本就没有代码,因此不会崩溃。你是以某种方式初始化int吗?

要查看发生崩溃的代码,您应该执行所谓的事后分析。

Windows错误报告

如果要分析崩溃,则应该进行崩溃转储。一个选项是注册Windows错误报告 - 需要一些钱(您需要一个数字代码签名ID)和一些表单填写。有关更多信息,请访问https://winqual.microsoft.com/

直接从客户

获取用于WER的故障转储

另一种选择是与一些正在经历崩溃的用户取得联系并直接从他那里获得用于WER的崩溃转储。用户可以在将崩溃发送给Microsoft之前单击技术详细信息时执行此操作 - 可以在那里检查崩溃转储文件位置。

您自己的minidump

另一种选择是注册自己的异常处理程序,处理异常并在任何地方编写minidump。详细说明可在Code Project Post-Mortem Debugging Your Application with Minidumps and Visual Studio .NET article找到。

答案 1 :(得分:5)

所以配置是DEBUG配置时它不会崩溃吗?有许多不同于RELEASE配置的东西: 1.)全局变量的初始化 2.)实际机器代码生成等。

因此,与DEBUG模式相比,第一步是找出RELEASE模式中每个参数的确切设置。

-AD

答案 2 :(得分:4)

  

1)崩溃只发生在Release版本中。

这通常表明您依赖某些不能保证的行为,但在调试版本中恰好是这样。例如,如果您忘记初始化变量,或者访问数组越界。确保已打开所有编译器检查(/ RTCsuc)。还要检查依赖于函数参数评估顺序的事情(不能保证)。

  

2)一旦删除所有与GDI相关的内容,崩溃就会消失。

也许这暗示你在GDI相关的东西上做错了什么?例如,你是否在被释放后使用HANDLEs?

答案 3 :(得分:2)

下载Debugging tools for Windows包。正确设置符号路径,然后在WinDbg下运行您的应用程序。在某些时候,它将破坏访问冲突。然后你应该运行命令“!analyze -v”,这很聪明,应该给你一个关于什么是错误的提示。

答案 4 :(得分:1)

大多数heisenbugs / release-only错误是由于控制流量取决于未初始化内存/过时指针/过去缓冲区末端或竞争条件或两者的读取。

尝试覆盖分配器,以便在分配时将内存清零。问题是否消失(或变得更可重复?)

  

写一个日志表明崩溃发生在一个本地int变量的声明中!怎么会这样?内存损坏?

堆栈溢出! ;)

答案 5 :(得分:1)

听起来像堆栈腐败给我。我最喜欢的跟踪它的工具是IDA Pro。当然,您无权访问用户的计算机。

一些内存检查程序很难捕获堆栈损坏(如果确实如此)。我认为最可靠的方法是运行时分析。

这也可能是由于异常路径中的损坏,即使处理了异常也是如此。您是否启用了“捕获第一次机会异常”?你应该尽可能长。在很多情况下,它会在一段时间后变得烦人。

您可以向这些用户发送已检查版本的应用程序吗?签出Minidump处理该异常并写出转储。然后使用WinDbg进行调试。

另一种方法是编写非常详细的日志。创建“记录每个操作”选项,并要求用户打开它并将其发送给您。将内存转储到日志中。在MSDN上查看'_CrtDbgReport()'。

祝你好运!

编辑:

回应你的评论:本地变量声明的错误对我来说并不奇怪。我已经看过很多了。这通常是由于堆栈损坏。

例如,堆栈上的某些变量可能会在其边界上运行。在那之后,所有的地狱都破裂了。然后堆栈变量声明会抛出随机内存错误,虚拟表会被破坏等等。

任何时候我都会看到那些延长的时间,我不得不去IDA Pro。 详细的运行时反汇编调试是我所知道的唯一真正可靠的。

许多开发人员使用WinDbg进行此类分析。这就是为什么我也建议使用Minidump。

答案 6 :(得分:1)

  4)写一个日志显示崩溃发生在一个本地int变量的声明上!怎么会这样?内存损坏

我发现许多“奇怪的崩溃”的原因是在所述对象的成员函数内取消引用损坏的this

答案 7 :(得分:1)

尝试Rational(IBM)PurifyPlus。它捕获了很多BoundsChecker没有的错误。

答案 8 :(得分:1)

坠机说什么?访问违规?例外?这将是用

解决这个问题的进一步线索

使用PageHeap.exe

确保没有先前的内存损坏

确保没有堆栈溢出(CBig数组[1000000])

确保没有未初始化的内存。

此外,一旦为流程生成调试符号(与创建调试版本不同),您也可以在调试器内运行发行版本。单步执行,查看是否在调试器跟踪窗口中收到任何警告。

答案 9 :(得分:1)

“4)编写日志表明崩溃发生在本地int变量的声明中!怎么可能?内存损坏?”

这可能表明硬件实际上有问题或被推得太猛。看看他们是否超频了他们的电脑。

答案 10 :(得分:1)

当我得到这种类型的东西时,我尝试通过gimpels PC-Lint(静态代码分析)运行代码,因为它检查BoundsChecker的不同类错误。如果您使用的是Boundschecker,请打开内存中毒选项。

你提到AMD CPU。您是否已经调查了崩溃的计算机上是否存在类似的图形卡/驱动程序版本和/或配置?它总是在这些机器上或偶尔会崩溃吗?也许在这些机器上运行系统信息工具,看看它们有什么共同点,