Click here to monitor SSC

Simon Cooper

Subterranean IL: Exception handler semantics

Published Monday, February 21, 2011 12:00 PM

In my blog posts on fault and filter exception handlers, I said that the same behaviour could be replicated using normal catch blocks. Well, that isn't entirely true...

Changing the handler semantics

Consider the following:

.try {
    .try {
        .try {
            newobj instance void [mscorlib]System.Exception::.ctor()
            
            // IL for:
            // e.Data.Add("DictKey", true)
            
            throw
        }
        fault {
            ldstr "1: Fault handler"
            call void [mscorlib]System.Console::WriteLine(string)
            endfault
        }
    }
    filter {
        ldstr "2a: Filter logic"
        call void [mscorlib]System.Console::WriteLine(string)
        
        // IL for:
        // (bool)((Exception)e).Data["DictKey"]
        
        endfilter
    }{
        ldstr "2b: Filter handler"
        call void [mscorlib]System.Console::WriteLine(string)
        leave.s Return
    }
}
catch object {
    ldstr "3: Catch handler"
    call void [mscorlib]System.Console::WriteLine(string)
    leave.s Return
}

Return:
  // rest of method

If the filter handler is engaged (true is inserted into the exception dictionary), then the following gets printed to the console:

2a: Filter logic
1: Fault handler
2b: Filter handler
and if the filter handler isn't engaged, then the following is printed:
2a:Filter logic
1: Fault handler
3: Catch handler

The filter handler is executed first. Hmm, ok. Well, what happens if we replaced the fault block with the C# equivalent (with the exception dictionary value set to false)?

.try {
    // throw exception
}
catch object {
    ldstr "1: Fault handler"
    call void [mscorlib]System.Console::WriteLine(string)
    rethrow
}
we get this:
1: Fault handler
2a: Filter logic
3: Catch handler

The fault handler is executed first, instead of the filter block.

Eh?

This change in behaviour is due to the way the CLR searches for exception handlers. When an exception is thrown, the CLR stops execution of the thread, and searches up the stack for an exception handler that can handle the exception and stop it propagating further - catch or filter handlers. It checks the type clause of catch clauses, and executes the code in filter blocks to see if the filter can handle the exception.

When the CLR finds a valid handler, it saves the handler's location, then goes back to where the exception was thrown and executes fault and finally blocks between there and the handler location, discarding stack frames in the process, until it reaches the handler.

So?

By replacing a fault with a catch, we have changed the semantics of when the filter code is executed; by using a rethrow instruction, we've split up the exception handler search into two - one search to find the first catch, then a second when the rethrow instruction is encountered.

This is only really obvious when mixing C# exception handlers with fault or filter handlers, so this doesn't affect code written only in C#. However it could cause some subtle and hard-to-debug effects with object initialization and ordering when using and calling code written in a language that can compile fault and filter handlers.

by Simon Cooper
Filed Under:

Comments

No Comments
You need to sign in to comment on this blog

About Simon Cooper

Simon joined Red Gate as a software developer in 2007. He started off in the SQL Tools division, working on SQL Compare 7 and 8, moved onto Schema Compare for Oracle, and is now in the .NET division working on SmartAssembly.
Latest articles
A first look at SQL Server 2012 Availability Group Wait Statistics
 If you are trouble-shooting an AlwaysOn Availability Group topology, a study of the wait statistics... Read more...

SQL Server Prefetch and Query Performance
 Prefetching can make a surprising difference to SQL Server query execution times where there is a high... Read more...

SSIS Basics: Setting Up Your Initial Package
 When working with databases, the use of SQL Server Integration Services (SSIS) is a skill that often... Read more...

Checking Out SQL Backup Pro 7’s New Automatic Backup Verification
 Wouldn't it be great to offload the daily chore of checking the integrity of your production... Read more...

Chuck Lathrope: DBA of the Day
 Chuck Lathrope was a finalist for the Exceptional DBA of the Year award in 2009. We contacted him to... Read more...