ASP.NET 2.0 Crash case study: Unhandled exceptions

For a long time all my case studies have been on 1.1. it’s time to venture out in 2.0 land and look at what may seem like a 2.0 specific issue.

I say “may seem” because this case study will only directly crash if you are using 2.0, but as you’ll learn later the problem existed in 1.1 and 1.0, it was just way harder to track down.

Problem description:

Once in a while ASP.NET crashes and we see events in the system event log like this one

Event Type: Warning
Event Source: W3SVC
Event Category: None
Event ID: 1009
Date: 2006-04-25
Time: 09:41:22
PM User: N/A
Computer: SUBSPACE1
Description:
A process serving application pool 'ASP.NET V2.0' terminated unexpectedly. The process id was ‘1732’. The process exit code was ‘0xe0434f4d’.

Or this one

Event Type: Warning

Event Source: W3SVC

Event Category: None

Event ID: 1011

Date: 2006-04-25

Time: 09:41:22

User: N/A

Computer: SUBSPACE1

Description:

A process serving application pool 'ASP.NET V2.0' suffered a fatal communication error with the World Wide Web Publishing Service. The process id was '6256'. The data field contains the error number.

And in the application event log we get a pretty cryptic error message like this one

Event Type: Error

Event Source: .NET Runtime 2.0 Error Reporting

Event Category: None

Event ID: 5000

Date: 2006-04-25

Time: 09:41:20

User: N/A

Computer: SUBSPACE1

Description:

EventType clr20r3, P1 w3wp.exe, P2 6.0.3790.1830, P3 42435be1, P4 app_code.pn5mfdcr, P5 0.0.0.0, P6 444dcf44, P7 5, P8 5, P9 system.dividebyzeroexception, P10 NIL.

Initial thoughts:

Ok, so what do we know about the issue? We know that asp.net terminated unexpectedly, and that right before this we got a System.DivideByZeroException…. We also know that the process exit code was 0xe0434f4d whatever that means, hmm…

Usually when you get a stopped unexpectedly error message the exit code will be the type of exception that caused the crash. For example a 0xC0000005 means you got a second chance access violation, 0x800703e9 means you suffered a StackOverflowException but what about 0xe0434f4d?

 

0xe0434f4d is the exception code for CLR (.net) exceptions, so any managed exception like a NullReferenceException or InvalidOperationException or SQLException… basically all managed exception are natively referred to as 0xe0434f4d. In this case, if we look closer at the application event log entry we can see that it is in fact a System.DivideByZero exception.

Trivia: Justa piece of info of no particular value that you might want to pull out of pocket on your next dateJ 0xe0434f4d or at least 43 4f 4d are the ASCII values for the letters COM.

But hey now… should a .net exception cause the asp.net process to crash??? If you divide by zero in your page and don’t have a try catch block around it, surely you will get one of those “nice” white and yellow error pages saying that an exception occurred on your page, but the process doesn’t just exit.

The answer is yes, you will get one of those pages because the asp.net global error handler will eventually catch your exception, format it for you and print it out on the screen. But what happens if it is not on an asp.net request, so there is no-one to feedback the exception to? It’s the old paradox: If a tree falls in the forest and nobody is there, does it still make a sound?

In 1.0 and 1.1 it didn’t. For example if you throw an exception in a piece of code called on a timer, or use QueueUserWorkItem and throw an exception in code executing there, or otherwise throw exceptions in code that is not running inside the context of an asp.net request, the framework will swallow the exception and continue. Or rather it will stop that thread of execution but it won’t die.

Doesn’t sound all that bad right? Really???

 

That thread could have been doing anything, and we will never be the wiser that it died. It could have been holding a lock of some sort, or it could have been in the middle of cleaning up resources, or really a number of different things that will now never happen, but that may immediately or eventually have really bad side effects like hangs or crashes or memory issues, but the exception will be long gone so we cant figure out what it was.

The policy for unhandled exceptions was changed in ASP.NET 2.0 to the default for .net which is a process exit. This can be changed back by adding the following to the aspnet.config in the frameworks directory, but I wouldn’t recommend it without putting in some preventive measures to take care of potential unhandled exceptions on non ASP.NET threads.

<configuration>

<runtime>

<legacyUnhandledExceptionPolicy enabled="true" />

</runtime>

</configuration>

Troubleshooting the issue:

The main task here is to find out where this DivideByZero exception is coming from and why it occurred so there are two ways to figure this out (short of complete code inspection).

Strategy #1 – logging the exception

The first way, and this is the way I would probably recommend, is to create an UnhandledExceptionHandler to log the exception along with its stack trace in the event log as shown in this article https://support.microsoft.com/?id=911816

You add the handler like this to the web.config:

    <system.web>

      <httpModules>

        <add type="WebMonitor.UnhandledExceptionModule, <strong name>" name="UnhandledExceptionModule"/>

      </httpModules>

    </system.web>

And it hooks an eventhandler up to the UnhandledException event of the current app domain.

You don’t actually need to strong name it and add it to the GAC, however if you plan it in multiple applications you should to avoid for the dll being loaded multiple times.

Now the next time you get one of these unhandled exceptions, the process will still exit (unless you change the unhandled exception policy), but you have a very good chance of fixing the issue.

The event for the exception in this particular sample looks like this…

Event Type: Error

Event Source: ASP.NET 2.0.50727.0

Event Category: None

Event ID: 0

Date: 2006-04-25

Time: 09:41:20

User: N/A

Computer: SUBSPACE1

Description:

UnhandledException logged by UnhandledExceptionModule.dll:

appId=/LM/w3svc/1/ROOT/CrashMe

type=System.DivideByZeroException

message=Attempted to divide by zero.

stack=

   at MyFinalizerClass.Finalize()

.

Bingo!!! So the exception occurs in MyFinalizerClass.Finalize() in the CrashMe application.

In fact the code for the finalizer for this class looks like this, so it is pretty obvious what caused it, and our work here is done…

    ~MyFinalizerClass()

    {

        int i = 0;

        int j = 9;

        i = j / i;

    }

Setting up an UnhandledException handler like this is not limited to 2.0. You can absolutely do this in 1.1 as well to determine if you are throwing any unhandl