9

请帮忙!我真的束手无策。我的程序是一个小小的个人笔记管理器(谷歌搜索“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 的机器上崩溃。我已将此选项设置为“未设置”,并且该错误消失了。呸!

非常感谢大家的帮助!!

4

11 回答 11

10

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

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

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

Windows 错误报告

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

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

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

你自己的小型转储

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

于 2008-09-25T08:46:59.983 回答
5

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

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

-广告

于 2008-09-25T08:38:13.093 回答
4

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

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

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

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

于 2008-09-25T08:43:52.173 回答
2

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

于 2008-09-25T10:09:38.833 回答
1

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

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

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

堆栈溢出!;)

于 2008-09-25T08:37:49.927 回答
1

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

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

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

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

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

祝你好运!

编辑:

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

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

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

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

于 2008-09-25T08:46:39.157 回答
1

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

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

于 2008-09-25T09:05:24.773 回答
1

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

于 2008-09-25T09:08:24.423 回答
1

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

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

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

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

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

于 2008-09-25T10:02:26.477 回答
1

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

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

于 2008-09-25T12:40:24.943 回答
1

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

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

于 2008-09-26T07:32:59.793 回答