Monday, January 12, 2009

Exceptions 101: StackOverflowException

Underwater cave exploration is notoriously dangerous. Because of this, divers who explore these caverns unravel string behind them as they swim, so they can find their way back to the surface at the end of their dive. .NET does something similar, creating a record of methods, adding and removing from this record as the application enters and exits specific methods. This trail is called the call stack, and at any given time, it shows what steps were taken that led to the current method. The difference between the diver and the application, however, is that when the diver runs out of string, he turns back and returns to the surface, but when too much stack has been laid down, the application throws a StackOverflowException.



The typical reason for a StackOverflowException is a recursive call made within the code. The following console application gives an example:


public class Program

{

    static void Main(string[] args)

    {

        RunA();

    }

 

    static void RunA()

    {

        RunB();

    }

    static void RunB()

    {

        RunA();

    }

}



Following the logic of this application, it's simple to see what happens. The main program calls a method called RunA, which in turn calls RunB, which in turn calls RunA, and so on and so forth. This loop never stops, so .NET stops it for you by throwing a StackOverflowException.

Now, here's the bad thing about a StackOverflowException, typically, in the IDE, whenever you try to view detail on a StackOverflowException, you get this really wonderful and informative line:

{Cannot evaluate expression because the current thread is in a stack overflow state.}

"Great," you say, "not only am I getting an exception, but I can't even view any information about it." Not only this, but you can't catch a StackOverflowException either. Sounds fun, huh?

There's no need to fret. In this situation, the simplest thing to do is to read the call stack from the call stack window. You can access this window by going to Debug -> Windows -> Call Stack, or by simply pressing Ctrl-Alt-C. When you view the call stack, you'll most likely notice that it's full. It probably has thousands of lines on it. The key here is to find the pattern which will most likely be there. In my small example above, the beginning of the call stack looks like this:



See the pattern? Granted, this is a very simplistic example, as there are only two methods recursively calling each other. Debugging this may take a little more effort in real life, however, and it may vary from situation to situation. I may have to ask myself why I'm calling RunB from RunA, and why I'm calling RunA from RunB. It could be that I don't really mean to call one from the other, and it could be that some condition I should have implemented to prevent one from calling the other at some point is never being evaluated in such a way as to stop the recursive calls. In any way, the key to at least finding this error is to take a look at the call stack, and read it until you start seeing it repeat itself, and somewhere in that loop, cut it off or redirect it to another method.

By the way, it's important to check your properties as well, as codependant properties can cause this very same error. Remember, property getters and setters are nothing more than prettied-up methods.

Happy debugging!