How to terminate a program when it crashes? (which should just fail a unit test instead of getting stuck forever)

后端 未结 3 1600
时光说笑
时光说笑 2020-11-27 03:33

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

相关标签:
3条回答
  • 2020-11-27 03:40

    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

    0 讨论(0)
  • 2020-11-27 03:44

    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");
    
            }
    
        }      
    }
    
    0 讨论(0)
  • 2020-11-27 03:51

    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.

    0 讨论(0)
提交回复
热议问题