Elegant handling of damaged state exceptions

Related to this question , I would like to force the CLR to allow my .NET 4.5.2 application to catch Corrupted State Exceptions for the sole purpose of registering them and then terminating the application. What is the right way to do this if I have catch (Exception ex) in several places around the application?

So, after I specify the <legacyCorruptedStateExceptionsPolicy> attribute, if I understand correctly, all catch (Exception ex) handlers will catch exceptions such as AccessViolationException and will happily continue.

Yes, I know that catch (Exception ex) is Bad Idea ™, but if the CLR at least puts the correct stack trace in the event log, I would be more than happy to tell the client that its server application does not work 1AM quickly and be Offline at night is good. But, unfortunately, the CLR logs an unrelated exception in the event log and then closes the process so that I cannot find out what actually happened.

The question is how to do this, the process is wide:

 if the exception thrown is a Corrupted State Exception: - write the message to the log file - end the process 

(Update)

In other words, this is likely to work for most exceptions in a simple application:

 [HandleProcessCorruptedStateExceptions] [SecurityCritical] static void Main() // main entry point { try { } catch (Exception ex) { // this will catch CSEs } } 

But this will not work for:

  • Unhandled application domain exceptions (i.e. thrown on threads without a foreground)
  • Windows Service applications (which do not have an actual Main entry point)

So, it seems that <legacyCorruptedStateExceptionsPolicy> is the only way to make this work, in which case I don’t know how the crash after registering the CSE?

+17
source share
2 answers

Instead of using <legacyCorruptedStateExceptionsPolicy> it would be better to use [HandleProcessCorruptedStateExceptions] (and [SecurityCritical] ), as indicated here:

https://msdn.microsoft.com/en-us/magazine/dd419661.aspx

After that, your Main method should look something like this:

 [HandleProcessCorruptedStateExceptions, SecurityCritical] static void Main(string[] args) { try { ... } catch (Exception ex) { // Log the CSE. } } 

But keep in mind that this does not catch more serious exceptions such as StackOverflowException and ExecutionEngineException .

Also, finally involved try blocks will not execute:

https://csharp.2000things.com/2013/08/30/920-a-finally-block-is-not-executed-when-a-corrupted-state-exception-occurs/

For other unhandled appdomain exceptions, you can use:

  • AppDomain.CurrentDomain.UnhandledException
  • Application.Current.DispatcherUnhandledException
  • TaskScheduler.UnobservedTaskException

(Please search for details when a particular handler is appropriate for your situation. For example, TaskScheduler.UnobservedTaskException little more complicated.)

If you don’t have access to the Main method, you can also tag the AppDomain exception handler to catch the CSE:

 AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; ... [HandleProcessCorruptedStateExceptions, SecurityCritical] private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { // AccessViolationExceptions will get caught here but you cannot stop // the termination of the process if e.IsTerminating is true. } 

The last line of defense may be an unmanaged UnhandledExceptionFilter as follows:

 [DllImport("kernel32"), SuppressUnmanagedCodeSecurity] private static extern int SetUnhandledExceptionFilter(Callback cb); // This has to be an own non generic delegate because generic delegates cannot be marshalled to unmanaged code. private delegate uint Callback(IntPtr ptrToExceptionInfo); 

And then somewhere at the beginning of your process:

 SetUnhandledExceptionFilter(ptrToExceptionInfo => { var errorCode = "0x" + Marshal.GetExceptionCode().ToString("x2"); ... return 1; }); 

More information on possible return codes can be found here:

https://msdn.microsoft.com/en-us/library/ms680634(VS.85).aspx

The “specialty” of UnhandledExceptionFilter is that it is not called if a debugger is connected. (At least not in my case with a WPF application.) Be aware of this.

If you set all the relevant ExceptionHandlers on top, you must log all exceptions that may be logged. For more serious exceptions (like StackOverflowException and ExecutionEngineException ) you should find a different path because the whole process is not possible after they have occurred. A possible way could be another process that monitors the main process and logs any fatal errors.

Additional hints:

+12
source

Thanks to @haindl for the fact that you can also decorate handler methods with the [HandleProcessCorruptedStateExceptions] attribute 1 so I made a small test application to confirm whether everything really works as intended by.

1 Note. . Most answers claim that I should also include the [SecurityCritical] attribute, although there were no behavior changes in the tests below ( [HandleProcessCorruptedStateExceptions] seemed to work just fine). However, I will leave both attributes below, as I assume that all these people knew what they were saying. This is a school example of the "Copied from StackOverflow" template in action.

The idea is to remove the <legacyCorruptedStateExceptionsPolicy> parameter from app.config , i.e. allow our external (initial) handlers (s) to catch the exception, register it, and then fail. Adding this parameter will allow your application to continue if you catch an exception in some internal handler, and this is not what you want : the idea is to get the exact information about the exceptions and then kill it.

I used the following method to throw an exception:

 static void DoSomeAccessViolation() { // if you have any questions about why this throws, // the answer is "42", of course var ptr = new IntPtr(42); Marshal.StructureToPtr(42, ptr, true); } 

1. Exception of exceptions from Main :

 [SecurityCritical] [HandleProcessCorruptedStateExceptions] static void Main(string[] args) { try { DoSomeAccessViolation(); } catch (Exception ex) { // this will catch all CSEs in the main thread Log(ex); } } 

2. Capturing all exceptions, including background topics / tasks:

 // no need to add attributes here static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += UnhandledException; // throw on a background thread var t = new Task(DoSomeAccessViolation); t.Start(); t.Wait(); } // but it important that this method is marked [SecurityCritical] [HandleProcessCorruptedStateExceptions] private static void UnhandledException(object sender, UnhandledExceptionEventArgs e) { // this will catch all unhandled exceptions, including CSEs Log(e.ExceptionObject as Exception); } 

I would recommend using only the latter approach and removing [HandleProcessCorruptedStateExceptions] from all other places in order to prevent getting into the wrong place. That is, if you have a try/catch somewhere and an AccessViolationException is AccessViolationException , you want the CLR to skip the catch and propagate to UnhandledException until the application ends.

+8
source

All Articles