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

Posted

技术标签:

【中文标题】Heisenbug:WinApi 程序在某些计算机上崩溃【英文标题】:Heisenbug: WinApi program crashes on some computers 【发布时间】:2010-09-13 00:36:39 【问题描述】:

请帮忙!我真的束手无策。 我的程序是一个小小的个人笔记管理器(谷歌为“cintanotes”)。 在某些计算机上(当然我不拥有它们),它在启动后立即崩溃并出现未处理的异常。 这些计算机没有什么特别之处,只是它们往往具有 AMD CPU。

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

这是关于这个“黑森虫”的肯定:

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

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

3) BoundChecker 没有任何抱怨。

4) 编写日志显示崩溃发生在声明局部 int 变量时!怎么可能?内存损坏?

任何想法将不胜感激!

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

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

代码中断

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

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

非常感谢大家的帮助!!

【问题讨论】:

看起来 Goldenmean 最接近答案。 【参考方案1】:

4) 写日志显示崩溃发生在声明局部 int 变量时!怎么可能?内存损坏?

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

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

Windows 错误报告

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

直接从客户那里获取用于 WER 的故障转储

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

您自己的小型转储

另一种选择是注册您自己的异常处理程序,处理异常并在您希望的任何地方编写一个小型转储。详细说明见Code Project Post-Mortem Debugging Your Application with Minidumps and Visual Studio .NET article。

【讨论】:

确保您在 RELEASE(以及调试)模式下为您的应用程序构建调试信息(PDB 文件)。确保为每个已发布版本保留一组 PDB,以便可以将它们与转储一起使用。也许使用本地符号服务器。投票给 Suma 回答 - 这是正确的! 谢谢,我将尝试使用 minidump 的最后一个想法。不幸的是我不习惯低级调试,所以我需要阅读更多关于此的内容......【参考方案2】:

所以配置为DEBUG配置时不会崩溃?与 RELEASE 配置有很多不同之处: 1.) 全局变量的初始化 2.) 生成的实际机器代码等。

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

-AD

【讨论】:

【参考方案3】:

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

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

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

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

【讨论】:

我确实遇到了 HFONT 句柄的一个问题,但在 BoundsChecker 向我指出后就解决了。但不幸的是,该错误并未受到此更改的影响。【参考方案4】:

下载Debugging tools for Windows 包。正确设置符号路径,然后在 WinDbg 下运行您的应用程序。在某些时候,它会因访问冲突而中断。然后你应该运行命令“!analyze -v”,它非常聪明,应该给你一个关于哪里出了问题的提示。

【讨论】:

我需要在有问题的机器上本地执行此操作吗?【参考方案5】:

大多数 heisenbugs/仅发布错误是由于依赖于未初始化内存/过时指针/缓冲区结束读取的控制流,或竞争条件,或两者兼而有之。

尝试覆盖您的分配器,以便它们在分配时将内存清零。问题是否会消失(或变得更具重现性?)

写日志显示崩溃发生在声明局部 int 变量时!怎么可能?内存损坏?

堆栈溢出! ;)

【讨论】:

感谢您的想法,我一定会朝这个方向进行调查【参考方案6】:

4) 写日志显示崩溃发生在声明本地 int 变量时!怎么可能?内存损坏

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

【讨论】:

您能否详细说明一下,“破这个”到底是什么? Alex, broken this 就像...这样:string ps = new string;删除ps; ps->清除()。当您进入 clear() 时,您会看到损坏的 this【参考方案7】:

崩溃说明了什么?访问冲突?例外 ?这将是解决此问题的进一步线索

使用 PageHeap.exe 确保您没有先前的内存损坏

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

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

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

【讨论】:

【参考方案8】:

"4) 写日志显示崩溃发生在声明局部 int 变量时!怎么可能?内存损坏?"

这可能表明硬件实际上存在故障或被推得太紧。看看他们是否超频了他们的电脑。

【讨论】:

我认为情况并非如此。它发生在许多未超频的 PC 上。【参考方案9】:

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

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

【讨论】:

【参考方案10】:

对我来说,这听起来像是堆栈损坏。我最喜欢的追踪工具是IDA Pro。当然,您没有访问用户机器的权限。

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

这也可能是由于异常路径中的损坏,即使异常已被处理。您是否在打开“捕获第一机会异常”的情况下进行调试?你应该尽可能长。在许多情况下,它确实会在一段时间后变得烦人。

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

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

祝你好运!

编辑:

回复您的评论:局部变量声明中的错误对我来说并不奇怪。我已经看到很多了。这通常是由于堆栈损坏。

例如,堆栈上的某些变量可能会超出其边界。在那之后,所有的地狱都崩溃了。然后堆栈变量声明会引发随机内存错误、虚拟表损坏等。

每当我看到这些内容很长一段时间后,我就不得不去 IDA Pro。 详细的运行时反汇编调试是我所知道的唯一真正可靠的东西。

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

【讨论】:

感谢您的所有想法。我已经写了一个日志,它指向一个 int 变量声明。我不是在开玩笑,是这样的代码: log 【参考方案11】:

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

【讨论】:

感谢您的想法。如何让它在演示模式下运行?它要求一个许可证服务器。 试用版下载在此:ibm.com/developerworks/downloads/r/rpp

以上是关于Heisenbug:WinApi 程序在某些计算机上崩溃的主要内容,如果未能解决你的问题,请参考以下文章

C# 在调试器中与正常执行的奇怪行为导致了 Heisenbug

确认后一次又一次收到来自Google Pub / Sub订阅的消息[Heisenbug]

WinAPI - 钩住鼠标

在没有 ASLR 的情况下寻找(内存,GC 相关)heisenbug 消失

带有 PIL 和裁剪和粘贴图片的特殊 Heisenbug

如何防止我的函数在RemoveDirectory()WINAPI中延迟删除?