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

时间:2020-03-06 14:42:33  来源:igfitidea点击:

请帮忙!我真的很机智。
我的程序是一个小小的个人笔记管理器(google表示" cintanotes")。
在某些计算机上(当然,我一无所有),它在启动后便因未处理的异常而崩溃。
这些计算机没有什么特别之处,只不过它们倾向于配备AMD CPU。

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

这是有关此" Heisenbug"的确定信息:

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

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

3)BoundChecker没有任何抱怨。

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

任何想法将不胜感激!

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

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

和代码中断

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

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

非常感谢大家的帮助!

解决方案

大多数heisenbugs /仅发行版的bug是由于控制流取决于未初始化的内存读取/陈旧的指针/缓冲区的末尾或者争用条件,或者两者兼而有之。

尝试覆盖分配器,以便它们在分配时将内存清零。问题是否消失(或者更容易重现?)

Writig a log shows that the crash happens on a declaration of a local int variable! How could that be? Memory corruption?

堆栈溢出! ;)

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

因此,第一步是找出与"调试"模式相比,"释放"模式下每个参数的确切设置是什么。

-广告

1) The crash happens only in the Release version.

这通常表明我们依赖于某些无法保证的行为,但在调试版本中确实是这样。例如,如果我们忘记初始化变量,或者访问数组超出范围。确保已打开所有编译器检查(/ RTCsuc)。还要检查诸如依赖函数参数求值顺序的事情(这不能保证)。

2) The crash goes away as soon as I remove all GDI-related stuff.

也许这暗示我们在与GDI相关的事情上做错了什么?例如,释放后是否正在使用HANDLE?

对我来说听起来像是堆栈损坏。我最喜欢的追踪这些的工具是IDA Pro。当然,我们无权访问用户的计算机。

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

这也可能是由于异常路径中的损坏导致的,即使处理了异常也是如此。我们是否在打开"捕获优先机会异常"的情况下进行调试?我们应该尽可能地保持长久。在很多情况下,一段时间后确实会令人烦恼。

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

另一种方法是编写非常详细的日志。创建一个"记录每个动作"的选项,并要求用户将其打开并发送给我们。将内存转储到日志中。在MSDN上签出" _CrtDbgReport()"。

祝你好运!

编辑:

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

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

每当我长时间查看这些内容时,都必须去IDA Pro。我知道,只有详细的运行时反汇编调试才能真正可靠地获​​得这些调试信息。

许多开发人员使用WinDbg进行这种分析。这就是为什么我还建议使用Minidump的原因。

4) Writig a log shows that the crash happen on a declaration of a local int variable! how could that be? Memory corruption?

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

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

Windows错误报告

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

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

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

你自己的小转储

另一种选择是注册我们自己的异常处理程序,处理异常并在我们希望的任何地方编写小型转储。有关详细说明,请参见使用Minidumps和Visual Studio .NET进行代码项目事后调试应用程序。

4) Writig a log shows that the crash happen on a declaration of a local int variable!how could that be? Memory corruption

我发现导致大量"奇怪崩溃"的原因是取消引用了该对象的成员函数中损坏的" this"。

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

车祸说了什么?违反访问权限?例外 ?那将是解决此问题的进一步线索

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

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

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

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

下载Windows调试工具包。正确设置符号路径,然后在WinDbg下运行应用程序。在某些时候,它将因访问冲突而中断。然后,我们应该运行命令"!analyze -v",该命令非常聪明,可以提示我们出了什么问题。

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

这可能表明硬件实际上有故障或者被推得太重。找出他们是否超频了他们的计算机。

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

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