我们的单元测试会触发子进程,有时这些子进程会崩溃。发生这种情况时,会弹出一个 Windows 错误报告对话框,并且该进程将保持活动状态,直到手动关闭为止。这当然可以防止单元测试终止。
如何避免这种情况?
下面是 Win7 中的示例对话框,其中包含常用设置:
如果我禁用 AeDebug
注册表项,JIT 调试选项消失:
如果我禁用检查解决方案(我似乎可以通过控制面板控制的唯一东西),它看起来像这样,但仍然出现并且仍然阻止程序死亡,直到用户按下某些东西。 WerAddExcludedApplication 据记录也具有此效果。
Our unit tests fire off child processes, and sometimes these child processes crash. When this happens, a Windows Error Reporting dialog pops up, and the process stays alive until this is manually dismissed. This of course prevents the unit tests from ever terminating.
How can this be avoided?
Here's an example dialog in Win7 with the usual settings:
If I disable the AeDebug
registry key, the JIT debugging option goes away:
If I disable checking for solutions (the only thing I seem to have control over via the control panel), it looks like this, but still appears and still stops the program from dying until the user presses something. WerAddExcludedApplication is documented to also have this effect.
发布评论
评论(3)
jdehaan 和 Eric Brown 的回答摘要,以及 这个问题(另请参阅这个问题):
注意 这些解决方案也可能会影响其他错误报告,例如无法加载 DLL 或打开文件。
选项 1:全局禁用
在整个用户帐户或计算机上全局工作,这既是优点也是缺点。
将
[HKLM|HKCU]\Software\Microsoft\Windows\Windows Error Reporting\DontShowUI
设置为 1。详细信息:WER 设置。
选项 2:禁用应用程序
需要修改崩溃程序,文档中将其描述为最佳实践,不适合库函数。
调用 SetErrorMode:
SetErrorMode(SetErrorMode (0) | SEM_NOGPFAULTERRORBOX);
(或使用SEM_FAILCRITICALERRORS
)。详细信息:禁用程序崩溃对话框 (解释了奇怪的呼叫安排)。选项 2a:禁用某个功能:
需要修改崩溃程序,需要 Windows 7/2008 R2(仅限桌面应用)或更高版本,文档中描述为优先于
SetErrorMode
,适合线程安全的库函数。调用并重置 SetThreadErrorMode:
更多信息:没有太多可用的?
选项 3:指定处理程序
需要修改崩溃的程序。
使用
SetUnhandledExceptionFilter
设置您自己的结构化异常处理程序,该处理程序只需退出,可能会报告并可能尝试进行清理。选项 4:捕获异常
需要修改崩溃的程序。仅适用于 .NET 应用程序。
将所有代码包装到全局 try/catch 块中。指定
HandleProcessCorruptedStateExceptionsAttribute
也可能是SecurityCriticalAttribute
捕获异常的方法。详细信息:处理损坏的状态异常注意 :这可能无法捕获由托管调试助手引起的崩溃;如果是这样,这些也需要在应用程序中禁用。
选项 5:停止报告流程
对整个用户帐户全局有效,但仅在受控持续时间内有效。
每当 Windows 错误报告进程出现时就终止它:
但这仍然不是完全无懈可击的,因为控制台应用程序可能会通过不同的错误消息崩溃,显然是由名为
NtRaiseHardError
的内部函数显示的:< img src="https://i.sstatic.net/fBsTI.png" alt="替代文字">
A summary from the answers by jdehaan and Eric Brown, as well as this question (see also this question):
N.B. These solutions may affect other error reporting as well, e.g. failure to load a DLL or open a file.
Option 1: Disable globally
Works globally on the entire user account or machine, which can be both a benefit and a drawback.
Set
[HKLM|HKCU]\Software\Microsoft\Windows\Windows Error Reporting\DontShowUI
to 1.More info: WER settings.
Option 2: Disable for the application
Requires modification to the crashing program, described in documentation as best practice, unsuitable for a library function.
Call SetErrorMode:
SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);
(or withSEM_FAILCRITICALERRORS
). More info: Disabling the program crash dialog (explains the odd arrangement of calls).Option 2a: Disable for a function:
Requires modification to the crashing program, requires Windows 7/2008 R2 (desktop apps only) or higher, described in documenation as preferred to
SetErrorMode
, suitable for a thread-safe library function.Call and reset SetThreadErrorMode:
More info: not much available?
Option 3: Specify a handler
Requires modification to the crashing program.
Use
SetUnhandledExceptionFilter
to set your own structured exception handler that simply exits, probably with reporting and possibly an attempt at clean-up.Option 4: Catch as an exception
Requires modification to the crashing program. For .NET applications only.
Wrap all code into a global try/catch block. Specify the
HandleProcessCorruptedStateExceptionsAttribute
and possibly also theSecurityCriticalAttribute
on the method catching the exceptions. More info: Handling corrupted state exceptionsNote: this might not catch crashes caused by the Managed Debugging Assistants; if so, these also need to be disabled in the application.
Option 5: Stop the reporting process
Works globally on the entire user account, but only for a controlled duration.
Kill the Windows Error Reporting process whenever it shows up:
This is still not completely bullet-proof though, because a console application may crash via a different error message, apparently displayed by an internal function called
NtRaiseHardError
:唯一的解决方案是在非常高的级别(对于每个线程)捕获所有异常并正确终止应用程序(或执行其他操作)。
这是防止异常逃逸您的应用程序并激活 WER 的唯一方法。
添加:
如果异常是您不希望发生的事情,您可以在另一个单元测试框架中使用
AssertNoThrow
(NUnit) 或类似的方法来包含触发子进程的代码。这样您也可以将其添加到您的单元测试报告中。在我看来,这是我能想到的最干净的解决方案。加法2:
正如下面的评论所示,我错了:你不能总是捕获异步异常,这取决于环境允许的情况。在 .NET 中,一些异常无法被捕获,这使得我的想法在这种情况下毫无价值...
对于 .NET:存在涉及使用 AppDomain 的复杂解决方法,导致 AppDomain 卸载而不是整个崩溃应用。太糟糕了...
http://www .bluebytesoftware.com/blog/PermaLink,guid,223970c3-e1cc-4b09-9d61-99e8c5fae470.aspx
http://www.develop.com/media/pdfs/developments_archive/AppDomains.pdf
编辑:
我终于明白了。在 .NET 4.0 中,您可以将 System.Runtime.ExceptionServices 中的
HandleProcessCorruptedStateExceptions
属性添加到包含 try/catch 块的方法中。这真的有效!也许不推荐但有效。The only solution is to catch all exceptions at a very high level (for each thread) and terminate the application properly (or perform another action).
This is the only way to prevent the exception from escaping your app and activating WER.
Addition:
If the exception is something you do not except to happen you can use an
AssertNoThrow
(NUnit) or alike in another Unit Test framework to enclose the code firing the child processes. This way you would also get it into your Unit test report. This is in my opinion the cleanest possible solution I can think of.Addition2:
As the comments below show, I was mistaken: you cannot always catch the asynchronous exceptions, it depends on what the environment allows. In .NET some exceptions are prevented from being caught, what makes my idea worthless in this case...
For .NET: There are complicated workarounds involving the use of AppDomains, leading to an unload of an AppDomain instead of a crash of the whole application. Too bad...
http://www.bluebytesoftware.com/blog/PermaLink,guid,223970c3-e1cc-4b09-9d61-99e8c5fae470.aspx
http://www.develop.com/media/pdfs/developments_archive/AppDomains.pdf
EDIT:
I finally got it. With .NET 4.0 You can add the
HandleProcessCorruptedStateExceptions
attribute from System.Runtime.ExceptionServices to the method containing the try/catch block. This really worked! Maybe not recommended but works.尝试设置
为 1。(您也可以在 HKLM 中设置相同的密钥,但需要管理员权限才能执行此操作。)
这应该会阻止 WER 显示任何 UI。
Try setting
to 1. (You can also set the same key in HKLM, but you need admin privs to do that.)
This should prevent WER from showing any UI.