In this post, I am not going to talk about how to throw/re-throw exceptions or even write the best practices on Exception handling, but I will go on with some of the hidden facts of exception handling which you might want to know and later on will involve IL to check how exceptions are generated.
The Basics
Exception handling is one of the weakest section of CLR. Even though I like most of the things that CLR brings to us, but I definitely disagree if the exception handling is one amongst it. Even the exception handling as been evolved with the system is enhanced very well recently with the introduction of Uncatchable Exceptions, RuntimeWrappedException, code contacts etc. Lets discuss some of the major enhancements to the exception system.
The .NET exception handling is made up of three sections :
- try : In this segment you need to write only the portion which can potentially throw errors.
- catch : This section can overload based on the type of Exception and will be used to handle the exception which occurred in the Try block.
- finally : This block executes irrespective of try and catch. We write the clean up tasks here as it ensures to run even anything occurs.
try { Console.WriteLine("This is In Try"); } catch (SystemException sex) { Console.WriteLine("This is catch with system exception : {0}", sex.ToString()); } catch (Exception ex) { Console.WriteLine("This is in Catch with exception: {0}", ex.ToString()); } finally { Console.WriteLine("In finally"); }
Now in the above code, you can see, I have intentionally placed two catch block one with SystemException and another with Exception even though the try block has no possibility to throw exceptions. Please note, the overloading for exception matches the exact exception type of probable base type from top to bottom. As System.Exception is the base to all exception in .NET you should leave it as the last exception overload. Apart from the try/catch, finally is optional block which lets you write code which executes irrespective of try /catch.
Note : If you don't want to handle the exception in your code, you can still use try / finally. .NET allows you to keep your finally with try block to ensure that every exception that occurs in your code will be handled by the caller. So if you keep catch, finally is optional, but if you omit catch, finally becomes mandatory. So in other words try comes with either catches or finally or both.
Based on the initial idea of Exception handling, Microsoft thought to categorize exception into
- System.SystemException
- System.ApplicationException
Uncatchable Exceptions
Now this is truly an interesting enhancement to Exception handling. Uncatchable exceptions are those which is treated as a bug in the system, and the process gets terminated when this exception occurs in your application. The Uncatchable exceptions cannot be handled using catch block, and you should also note these exceptions doesn't even allow the finally block to execute.
StackOverflowException : CLR 2.0 does not allow you to catch StackOverflowException for your application. It is treated as a bug in your application which you need to fix immediately. The application gets terminated when this exception occurs.
static void Main(string[] args) { try { Console.WriteLine("This is In Try"); Program p = new Program(); p.ExecuteOverflow(new Program()); } catch (SystemException sex) { Console.WriteLine("This is catch with system exception : {0}", sex.ToString()); } catch (Exception ex) { Console.WriteLine("This is in Catch with exception: {0}", ex.ToString()); } finally { Console.WriteLine("In finally"); } } public void ExecuteOverflow(Program p) { p.ExecuteOverflow(new Program()); }
Just if I replace the code with the one above, you will see that the application will terminate without writing "In finally" and no catch (even though Exception is the base for StackOverflowException) never been caught.
In CLR 4.0, Microsoft added another uncatchable exception called AccessViolationException which can also never be caught.
When an uncaught exception occurs in the system, Microsoft by default writes the entire exception in System's event log before terminating the process. You can see the log from Control Panel -> Administrative Tools -> Event Viewer. A sample exception log is shown below :
Here it shows that stack overflow occurred in ExceptionHandlingDemo with the helplink for Microsoft Support.
Note : You should note, even though some people says OutOfMemoryException is also uncatchable, but it isnt. CLR still allows you to catch OutOfMemoryException which lets you handle memory related issues.
Can I make an Uncatchable Exception?
This is the most general question that appears in mind while talking about Uncatchable Exceptions. Yes there is option. Environment.FailFast is a method which lets you to create an UncatchableException. If your application produce a corrupted state which could not be recovered, you could either use AppDoman.Unload to unload the domain in which the Thread is running, or use Environment.FailFast to terminate the entire process with an entry in EventLog.
Dealing with Corrupted State Exceptions in .NET 4.0
Well, If you are reading this article from first, I have told you that CLR will not allow finally block to execute when the Corrupted State Exception like StackOverflowException, AccessViolationException, etc With the rarely used class HandleProcessCorruptedStateExceptions you will have now the option to log the Corrupted State Exceptions and continue running the process (even though it is not recommended). If you want to learn more about it you can read this post.
Note : CLR is also very smart enough to wrap around the runtime exception that comes from unmanaged code and wrap around into RuntimeWrappedException.
The Internals
Now moving back to internals of Exception handling, IL has a specific section for try/catch/finally. Just lets see the IL for the code specified first :
The IL is very straight forward. You can see every block has a leave.s which lets the control to jump L_003c which is finally block. Hence if no exception occurs, the control will jump from L_000e to L_003c. The last section of the IL lists all the possible try/catch path which the program can traverse. Each catch block has a handler associated with respective .try. The one that first lists is System.SystemException while the last lists the normal execution.
As when the exception is encountered, the CLR finds the proper handler based on the list from top to bottom, it is essential to have more specific exception above in the list.
Another important point here to note, try/catch puts a scope around the instruction sets. There are lots of C# constructs are also using try/catch/finally to actually take its advantage. using statement is actually a try/finally with Dispose called inside finally block, even foreach is also the same thing. lock statement on the other hand invokes Monitor.Exit inside finally.
Conclusion
Even though there are many things that I have to discuss before point actually comes to an end, I will share them in a separate post. Exception handling is very important section for any program. I hope you like the post and stay tune for more about it.
Thank you for reading.
Nice explanation Abhishek. Thanks. Liked this post. Hope many to come from you.
ReplyDeleteVery Nicely Explained Abhishek.Uncatchable exception have enhanced my vocabulary
ReplyDeleteKamran Shahid
microsoft recommends to use System.ApplicationException for Custom Exceptions to inherit
ReplyDeleteI dont think users usually inherit System.Exception
microsoft recommends to use System.ApplicationException for Custom Exceptions to inherit.
ReplyDeleteI dont think users usually inherit System.Exception
@suresh kumar
ReplyDeleteMost of the custom exceptions are built inheriting from System.Exception. As per I know, I saw even many libraries does this mistake.