Gracefully handling corrupted state exceptions

前端 未结 3 1775
遇见更好的自我
遇见更好的自我 2020-11-27 17:50

Related to this question, I would like to force CLR to let my .NET 4.5.2 app catch Corrupted State Exceptions, for the sole purpose of logging them and then terminating the

3条回答
  •  旧巷少年郎
    2020-11-27 18:32

    Thanks to @haindl for pointing out that you can also decorate handler methods with the [HandleProcessCorruptedStateExceptions]1 attribute, so I made a little test app just to confirm if things really work as they are supposed to.

    1 Note: Most answers state that I should also include the [SecurityCritical] attribute, although in the tests below omitting it didn't change the behavior (the [HandleProcessCorruptedStateExceptions] alone seemed to work just fine). However, I will leave both attributes below since I am presuming all these folks knew what they were saying. That's a school example of "Copied from StackOverflow" pattern in action.

    The idea is, obviously, to remove the setting from app.config, i.e. only allow our outermost (entry-level) handler(s) to catch the exception, log it, and then fail. Adding the setting will allow your app to continue, if you catch the exception in some inner handler, and this is not what you want: the idea is just to get the accurate exception info and then die miserably.

    I used the following method to throw the 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. Catching 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. Catching all exceptions, including background threads/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's 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 just the latter approach, and removing the [HandleProcessCorruptedStateExceptions] from all other places to make sure the exception doesn't get caught at the wrong place. I.e. if you have a try/catch block somewhere and an AccessViolationException is thrown, you want CLR to skip the catch block and propagate to the UnhandledException before ending the app.

提交回复
热议问题