当程序崩溃时如何终止它? (这应该只是单元测试失败而不是永远卡住)

发布于 2024-09-16 07:41:04 字数 708 浏览 6 评论 0 原文

我们的单元测试会触发子进程,有时这些子进程会崩溃。发生这种情况时,会弹出一个 Windows 错误报告对话框,并且该进程将保持活动状态,直到手动关闭为止。这当然可以防止单元测试终止。

如何避免这种情况?


下面是 Win7 中的示例对话框,其中包含常用设置:

alt text

如果我禁用 AeDebug 注册表项,JIT 调试选项消失:

alt text

如果我禁用检查解决方案(我似乎可以通过控制面板控制的唯一东西),它看起来像这样,但仍然出现并且仍然阻止程序死亡,直到用户按下某些东西。 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:

alt text

If I disable the AeDebug registry key, the JIT debugging option goes away:

alt text

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.

alt text

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

段念尘 2024-09-23 07:41:04

jdehaan 和 Eric Brown 的回答摘要,以及 这个问题(另请参阅这个问题):

注意 这些解决方案也可能会影响其他错误报告,例如无法加载 DLL 或打开文件。

选项 1:全局禁用

在整个用户帐户或计算机上全局工作,这既是优点也是缺点。

[HKLM|HKCU]\Software\Microsoft\Windows\Windows Error Reporting\DontShowUI 设置为 1。
详细信息:WER 设置

选项 2:禁用应用程序

需要修改崩溃程序,文档中将其描述为最佳实践,不适合库函数。

调用 SetErrorModeSetErrorMode(SetErrorMode (0) | SEM_NOGPFAULTERRORBOX);(或使用 SEM_FAILCRITICALERRORS)。详细信息:禁用程序崩溃对话框 (解释了奇怪的呼叫安排)。

选项 2a:禁用某个功能

需要修改崩溃程序,需要 Windows 7/2008 R2(仅限桌面应用)或更高版本,文档中描述为优先于 SetErrorMode ,适合线程安全的库函数。

调用并重置 SetThreadErrorMode

DWORD OldThreadErrorMode = 0;
SetThreadErrorMode(SEM_FAILCRITICALERRORS,& OldThreadErrorMode);
    …
SetThreadErrorMode (z_OldThreadErrorMode, NULL);

更多信息:没有太多可用的?

选项 3:指定处理程序

需要修改崩溃的程序。

使用 SetUnhandledExceptionFilter设置您自己的结构化异常处理程序,该处理程序只需退出,可能会报告并可能尝试进行清理。

选项 4:捕获异常

需要修改崩溃的程序。仅适用于 .NET 应用程序。

将所有代码包装到全局 try/catch 块中。指定 HandleProcessCorruptedStateExceptionsAttribute 也可能是 SecurityCriticalAttribute 捕获异常的方法。详细信息:处理损坏的状态异常

注意 :这可能无法捕获由托管调试助手引起的崩溃;如果是这样,这些也需要在应用程序中禁用。

选项 5:停止报告流程

对整个用户帐户全局有效,但仅在受控持续时间内有效。

每当 Windows 错误报告进程出现时就终止它:

var werKiller = new Thread(() =>
{
    while (true)
    {
        foreach (var proc in Process.GetProcessesByName("WerFault"))
            proc.Kill();
        Thread.Sleep(3000);
    }
});
werKiller.IsBackground = true;
werKiller.Start();

但这仍然不是完全无懈可击的,因为控制台应用程序可能会通过不同的错误消息崩溃,显然是由名为 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 with SEM_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:

DWORD OldThreadErrorMode = 0;
SetThreadErrorMode(SEM_FAILCRITICALERRORS,& OldThreadErrorMode);
    …
SetThreadErrorMode (z_OldThreadErrorMode, NULL);

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 the SecurityCriticalAttribute on the method catching the exceptions. More info: Handling corrupted state exceptions

Note: 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:

var werKiller = new Thread(() =>
{
    while (true)
    {
        foreach (var proc in Process.GetProcessesByName("WerFault"))
            proc.Kill();
        Thread.Sleep(3000);
    }
});
werKiller.IsBackground = true;
werKiller.Start();

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:

alt text

遮云壑 2024-09-23 07:41:04

唯一的解决方案是在非常高的级别(对于每个线程)捕获所有异常并正确终止应用程序(或执行其他操作)。

这是防止异常逃逸您的应用程序并激活 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 块的方法中。这真的有效!也许不推荐但有效。

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.ExceptionServices;

namespace ExceptionCatching
{
    public class Test
    {
        public void StackOverflow()
        {
            StackOverflow();
        }

        public void CustomException()
        {
            throw new Exception();
        }

        public unsafe void AccessViolation()
        {
            byte b = *(byte*)(8762765876);
        }
    }

    class Program
    {
        [HandleProcessCorruptedStateExceptions]
        static void Main(string[] args)
        {
            Test test = new Test();
            try {
                //test.StackOverflow();
                test.AccessViolation();
                //test.CustomException();
            }
            catch
            {
                Console.WriteLine("Caught.");
            }

            Console.WriteLine("End of program");

        }

    }      
}

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.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.ExceptionServices;

namespace ExceptionCatching
{
    public class Test
    {
        public void StackOverflow()
        {
            StackOverflow();
        }

        public void CustomException()
        {
            throw new Exception();
        }

        public unsafe void AccessViolation()
        {
            byte b = *(byte*)(8762765876);
        }
    }

    class Program
    {
        [HandleProcessCorruptedStateExceptions]
        static void Main(string[] args)
        {
            Test test = new Test();
            try {
                //test.StackOverflow();
                test.AccessViolation();
                //test.CustomException();
            }
            catch
            {
                Console.WriteLine("Caught.");
            }

            Console.WriteLine("End of program");

        }

    }      
}
揽清风入怀 2024-09-23 07:41:04

尝试设置

HKCU\Software\Microsoft\Windows\Windows 错误报告\DontShowUI

为 1。(您也可以在 HKLM 中设置相同的密钥,但需要管理员权限才能执行此操作。)

这应该会阻止 WER 显示任何 UI。

Try setting

HKCU\Software\Microsoft\Windows\Windows Error Reporting\DontShowUI

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文