我依靠Windows错误报告来为大型多线程应用程序创建完整的用户模式转储。我知道,当我开始使用它时(2012年初),这些转储包含所有应用程序内存,以及应用程序崩溃时(抛出未处理的异常等)所有线程的完整堆栈。但在去年的某个未知时刻,由WER创建的崩溃转储发生了变化。它们仍然包含所有内存,但只显示一个线程,堆栈似乎来自,在之后,进程已经关闭:
ntdll.dll!_LdrpCallInitRoutine@16() + 0x14 bytes
ntdll.dll!_LdrShutdownProcess@0() + 0x141 bytes
ntdll.dll!_RtlExitUserProcess@4() + 0x74 bytes
kernel32.dll!_UnhandledExceptionFilter@4() + 0x18928 bytes
这是一个用VS2010 SP1编译的非托管(不可管理?)32位c++应用程序,运行在64位Win7 SP1上(并保持更新)。有人知道去年有什么Windows更新改变了WER的行为吗?除了"HKLMSOFTWAREMicrosoftWindowsWindows错误报告LocalDumpsAppName.exe"之外,还有其他可配置的东西吗?
此外,通过调用'RaiseFailFastException'来终止应用程序仍然会产生一个良好的转储,并为所有线程提供有效的堆栈。
啊哈!第三方库正在调用SetUnhandledExceptionFilter,这阻止了Windows错误报告获得原始异常。它们的处理程序做了一些内部清理,然后调用abort,此时WER最终能够创建转储。
对于遇到这种问题的任何人,我建议检查已安装的处理程序(SetUnhandledExceptionFilter, set_terminate等的返回值)是否符合您的期望(如果您依赖于WER,或您自己的处理程序或CrashRpt,则为空)。
最好在应用程序崩溃时设置为自转储编写器。你只需要调用SetUnhandledExceptionFilter函数,指定回调。回调时使用MiniDumpWriteDump函数,MiniDumpWithFullMemory
转储类型
异常过滤器将在发生未处理(由代码)异常时调用。在回调中,最好枚举并挂起进程的所有其他线程。
您可能还需要为SetUnhandledExceptionFilter
本身安装一个钩子!为什么?好吧,CRT总是禁用任何安装的异常过滤器,并且通过钩函数,您可以避免这种情况。