The Uncatchable Exception
There's once aspect of exception handling that I've found that many seasoned .NET veterans know about. Take a look at the following code...
class Node { private Node node; public Node ChildNode { get { if (node == null) { node = new Node( ); } return node; } set { node = value; } } } class Program { static void ProcessNode(Node node) { ProcessNode(node.ChildNode); } static void Main(string[] args) { try { ProcessNode(new Node( )); } catch (StackOverflowException ex) { Console.WriteLine(ex.Message); } catch (Exception ex) { Console.WriteLine(ex.Message); } } }
Code Segment 1
What do you figure the output will be? Well, most people say the output is something like "Operation caused a stack overflow." That's a nice guess, but this exception thrown from the CLR is actually not catchable. This is the uncatchable exception. It actually jumps directly outside of your try block and shuts your application down. What you actually see is what's in the below figure.
Figure 1
The CLR does not allow you to have infinite loops in your applications at all. So much so in fact that it will literally kill your entire application to make sure you follow the rules.
Now, if you're thinking about it... you may be think "CLR threw it? Hmm... I wonder... I read something about the ability to throw things that aren't exceptions". So, you may be tempted to try this...
try { ProcessNode(new Node( )); } catch { Console.WriteLine("Unknown exception"); }
Code Segment 2
This actually doesn't help the situation at all. Actually, if you've read my previous blog entry on the RuntimeWrappedException, then you would know about the .NET wrapping plan. Under .NET's default rules, thrown objects which do not inherit from System.Exception are wrapped in an instance of RuntimeWrappedException. So, even if the exception thrown was one of those, it would have been caught by the original code anyhow.
This StackOverFlowException application failure is actually a very helpful rule the CLR enforces. It forces you to go back and make sure you don't have a recursion bug in your code, because this is not really a user-specific exception it's literally a bug in your application. So, before you throw a fit when you see this, just go back and find the bug in your recursion code.
It's important to note however, that there's nothing inherently special about the StackOverFlowException itself. Take a look at this code...
static void ThrowStackOverFlowException( ) { throw new StackOverflowException( ); } static void Main(string[] args) { try { ThrowStackOverFlowException( ); } catch (StackOverflowException ex) { Console.WriteLine(ex.Message); } }
Code Segment 3
This time your output really is "Operation caused a stack overflow.". So, if you throw it yourself you can catch it. The uncatchable exception isn't really StackOverflowException, but rather the CLR's throwing of the StackOverflowException.
There are other ways to completely kill an application. One of the more subtle of ways is via use of System.Environment.FastFail(String message). This static method will immediately kill and application and will not be caught by any catch blocks anywhere. So, if you really want to screw up an application simply do the following...
[Serializable] public class SalesOrderException : Exception { public SalesOrderException( ) { Environment.FailFast(String.Empty); } // More constructors go here... }
Code Segment 4
Now every time your application has a SalesOrderException, it will explode into pieces. There's absolutely no way to recover from this. The above code is something that a disguntled employee would love to check in.
That said, looking at it in another light, Environment.FastFail(String) can actually be a great debugging tool. For example, say you have an application that is just downright giving you some weird output. You have no idea why. You know it's wrong, but there are just no exceptions bubbling to the surface to help you out. Well, if you have access to Visual Studio 2005's Debug->Exceptions... menu item, you can actually tell Visual Studio to allow you to see those first chance exceptions. If you don't have that, however you can put Environment.FastFail(String) in an exception, and use deductive reasoning and process of elimination to find out where your problem in.
You may actually be wondering "What is the point of Environment.FastFail(String)?" It's actually quite useful for anyone severely uptight about security or someone withing really low level in a system. If you're absolutely sure there's an unrecoverable corruption in your system, then you can call this method to kill this application. Basically what you're doing is "blue screening your application". The operating system is untouched, but you application is gone. Another situation someone can use Environment.FastFail in in security situations. If you absolutely need to verify some piece of security for the application to continue at all (i.e. you don't want anyone to catch an exception you throw and continue insecure), then you can use this method to "bluescreen" the app.