34

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

Roman Starkov
  • 52,420
  • 33
  • 225
  • 300
  • 1
    How are you calling WerAddExcludedApplication? – Eric Brown Aug 31 '10 at 18:08
  • @Eric I'm afraid I have since deleted my extern declaration, and there isn't one on pinvoke.net. So I can't say exactly how I called it last time. It seems to be a red herring though; it appears to only disable the _send report_ bit, not the whole crash dialog. – Roman Starkov Aug 31 '10 at 18:26

3 Answers3

56

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

Community
  • 1
  • 1
Roman Starkov
  • 52,420
  • 33
  • 225
  • 300
  • Does SetErrorMode() affects also critical errors (like access violation) made by threads in C++? – Vladislav Rastrusny Mar 11 '11 at 16:06
  • @Frac I'm afraid I don't remember now. I think it does as long as your program doesn't use SetUnhandledExceptionFilter and displays its own message there. – Roman Starkov Mar 11 '11 at 17:31
  • Especially when you're locked-in by an old framework (for example VCL6), this `SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);` works best. @romkyns you made my day :-) – Wolf Jul 02 '15 at 09:55
  • 2
    The "entry point not found" and "system error" ("...dll is missing from your computer") dialog boxes seem to get suppressed with ```reg add HKLM\SYSTEM\CurrentControlSet\Control\Windows /v ErrorMode /t REG_DWORD /f /d 2```. They are not affected by the DontShowUI registry setting. – eel ghEEz Dec 20 '17 at 23:33
5

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");

        }

    }      
}
jdehaan
  • 19,108
  • 6
  • 54
  • 94
  • 1
    I suppose that would work in most cases, but what about StackOverflowException and AccessViolationException, which are uncatchable? – Roman Starkov Aug 24 '10 at 23:05
  • Even these exceptions should be catchable. In C++ this might imply the use of asynchronous exceptions (`/EHa` flag for the MSVC++ compiler for example, see http://msdn.microsoft.com/en-us/library/1deeycx5.aspx). Becoming so technical, the question is not language agnostic anymore. In .NET you can catch these exceptions without tweaking around. – jdehaan Aug 24 '10 at 23:22
  • 1
    @jdehaan [I'm pretty sure](http://pastebin.com/paPChDsx) you [can't](http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx) in .NET. Not sure about C++. I'm trying to stay agnostic, but it seems your recommendation is dependent on language specifics... – Roman Starkov Aug 24 '10 at 23:49
  • @romkyns, Ouch... In the very old past it worked in .NET, now not anymore. I understand the "technical reasons" behind, but sometimes you just have recursions and cannot control how deep they might become. I begin to dislike .NET regarding this... Thanks for the info, I really didn't know it until now! – jdehaan Aug 25 '10 at 05:36
  • Thanks for the snippets I experimented around... There seems to be a way so save the app from crashing with appdomains but that isn't funny. At least I learned a lot with your question. Unfortunately I cannot give more than a +1 to it, it is really really good. – jdehaan Aug 25 '10 at 08:32
  • @jdehaan Glad you enjoyed this question! Thanks for the link, that was a good read. – Roman Starkov Aug 25 '10 at 08:50
  • 1
    I found another very interesting document located here: http://www.develop.com/media/pdfs/developments_archive/AppDomains.pdf. Funny that I didn't realize the behaviour was completely changed since .NET 2.0... – jdehaan Aug 25 '10 at 09:50
  • It worked with StackOverflow and Accessviolation now but not with the code from http://stackoverflow.com/questions/2950130/how-to-simulate-a-corrupt-state-exception-in-net-4. At least a bit of progress. – jdehaan Sep 01 '10 at 14:54
  • Great find! Didn't know of that one. – Roman Starkov Sep 01 '10 at 21:11
  • Did you have success with the AppDomain workaround? for me this doesn't work for these exceptions, not only the AppDomain is unloaded but the whole Application was torn down! Is the AppDomain separation a myth? :-) Unfortunately I will have less time to dig into that next weeks. I hope I could help a bit. I also strongly want to understand this to 100%. – jdehaan Sep 02 '10 at 07:11
  • @jdehaan Indeed, the AppDomain isolation doesn't appear to be quite as good as the process isolation. By the way, +1 on your answer and I've posted a community wiki answer of my own summarizing all the answers I've found. – Roman Starkov Sep 03 '10 at 16:32
  • Note that it seems that this answer implies that the `StackOverflowException` can caught using `HandleProcessCorruptedStateExceptions`. Unfortunately, that's not true, it won't be caught (try it out). Some other CSE's are caught though. – Abel Jun 20 '12 at 18:20
3

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.

Eric Brown
  • 13,308
  • 7
  • 28
  • 67