Thursday, February 28, 2013

Tips and Tricks of Exception Handling in .Net - Part 3

This is the continuation of my article Tips and Tricks of Exception Handling in .Net - Part 2

Fail Fast Method: There are situations where your application's state is very bad and no code should be executed further - not even finally block code and your application needs to be closed immediately. How you do this?
           The answer is Environment's FailFast method. As the name suggests, this  is a special method which causes your application to fail immediately. It also creates a dump and event viewer entry.
 try 
 {
     Environment.FailFast("Text to be logged");
 }
 finally
 {
     Console.WriteLine("This finally block will not be executed.");
 }
Compile above code and execute the generated .exe you will see the following windows prompt, which you get usually when your application is having unhandled exception.















Process.GetCurrentProcess().Kill() vs Environment.FailFast(""): The finally block will not be executed even if you use Process.GetCurrentProcess().Kill() and this also ends your application immediately, then how it differs from FailFast? well, the difference is - FailFast will create a dump and event viewer entry but killing the current process will not.

Note: The both should be used with extensive care. In real-world these are required very rarely.


Corrupted State Exceptions (CSE): These are the exceptions which cannot be catched. Behind the scene Environment's FailFast method throws one of these exceptions. Hence, it cannot be catched and your application ends with an unhandled exception.

Here is the explaination of CSE by Jffrey Richter's words:
      Usually, CLR considers few exceptions thrown by native code as Corrupted State Exceptions, because they are usually the result of a bug in the CLR itself or in some native code for which the managed developer has no control over. Here is the list of native Win32 exceptions that are considered CSEs:

EXCEPTION_ACCESS_VIOLATION        EXCEPTION_STACK_OVERFLOW
EXCEPTION_ILLEGAL_INSTRUCTION     EXCEPTION_IN_PAGE_ERROR
EXCEPTION_INVALID_DISPOSITION     EXCEPTION_NONCONTINUABLE_EXCEPTION
EXCEPTION_PRIV_INSTRUCTION        STATUS_UNWIND_CONSOLIDATE

By default, the CLR will not let managed code catch these exceptions and finally blocks will not execute. However, Individual managed methods can override the default and catch these exceptions by applying the System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute to the method. In addition, the method must have the System.Security. SecurityCriticalAttribute applied to it. You can also override the default for an entire process by setting the legacyCorruptedStateExceptionPolicy element in the application’s Extensible Markup Language (XML) configuration file to true. The CLR converts most of these to a System.Runtime.InteropServices.SEHException object except for EXCEPTION_ACCESS_VIOLATION, which is converted to a System.AccessViolationException object, and EXCEPTION_STACK_OVERFLOW, which is converted to a System.StackOverflowException object.

Note: Even with the attribute HandleProcessCorruptedStateExceptions, we cannot handle the following exceptions, for a given reason:

  • StackOverflowException - As this is a hardware failure and there is no more stack available for further processing (Thanks Abel Braaksma for pointing this out).
  • ExecutionEngineException - It occurs because of heap memory corruption and hence cannot be handled further (Reference).

Summery:
  • Structured Exception Handling - This is the exception handling mechanism which is offered by Microsoft Windows and .Net Framework Exception Handling is built on the top of it.
  • What can be thrown? - The CLR allows an instance of any type to be thrown. But CLS mandates to throw only the Exception derived objects. The C# compiler allows to throw only exception derived types.
  • Throw different exception than the originally thrown one, when you want to maintain the meaning of a methods contract.
  • Make sure to set original exception as inner exception when you throw a different exception.
  • Constrained Execution Regions - Make sure that your catch or finally block will never throw an exception by making use of CER. You can use it by calling RuntimeHelpers's PrepareConstrainedRegions method and applying ReliabilityContract attribute wherever required.
  • The C# language automatically emits try/finally blocks whenever you use the lock, using, and foreach statements.
  • Call Environment's FailFast method when you want your application to be closed immediately and put a dump with event viewer entry.

2 comments:

  1. This post, and the quote from Richter, suggest that it is possible to catch a StackOverflowException when using HandleProcessCorruptedStateExceptionsAttribute. This is not true. When a (real) SO happens (as opposed to a manually raised SOE), the StackOverflowException is raised and the runtime will FailFast the whole process. No further processing of any managed code or finalizers will be executed, not even critical finalizers.

    This behavior is slightly different when the CLR is hosted, in which case the host may decide differently. The softest approach the host can decide upon though, is to issue a Rude AppDomain unload. This will run critical finalizers, but only when the code isn't run in the default application domain.

    ReplyDelete
    Replies
    1. Thanks for pointing this out (It was me who messed-up, not Richter). I updated the article.

      Delete