Heisenbug:WinApi程序在某些计算机上崩溃
请帮忙!我真的很机智。
我的程序是一个小小的个人笔记管理器(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。我们是否调查过崩溃的计算机上是否有类似的图形卡/驱动程序版本和/或者配置?它是总是在这些机器上崩溃还是偶尔崩溃?也许在这些机器上运行系统信息工具,看看它们有什么共同点,