--> MSIL: try..filter..fault - Impersonation Failure

MSIL: try..filter..fault

My colleague, Mike, recently pointed out to me that there is certain structured exception handling (SEH) clauses available in Microsoft's Intermediate Language (MSIL) that is not neccessarily available in all the CLI languages.

As an example, one of theses clauses, the filter clause, is available in Visual Basic.NET (When) and C++/CLI but not available in the C# language. Basically what a filter allows you is to execute some code and based on the outcome of that code decide whether to engage the exception handler clause.

0x0001 A dedicated block of the IL code, called filter, will process the exception and define whether the handler should be engaged. The offset of the filter block is specified in the FilterOffset entry. Since we cannot specify the filter block length—the EH clause structure contains no entry for it—a positioning limitation is associated with the filter block: the respective handler block must immediately follow the filter block, allowing the length of the filter block to be inferred from the offset of the handler. The filter block must end with the endfilter instruction, described in Chapter 10, "IL Instructions." At the moment endfilter is invoked, the evaluation stack must hold a single int32 value, equal to 1 if the handler is to be engaged and equal to 0 otherwise. This EH clause type is called a filter type. Branching into or out of the filter block is illegal. [From Inside Microsoft.NET IL Assembler by Serge Liden (No Blog)]

 

I've been looking for a scenario where this might come in useful and after reading Abhinaba Basu's blog on C#:try and retry I found a possible scenario where a filter block might be useful.

In the sample below the very secure password checking code is throwing an exception when the password entered doesn't match the hard-coded password "secret". The execution engine of the runtime then determines whether the exception happened in a guarded clause, which indeed it has. It then checks whether the handler specified for that clause will process the exception* by putting the exception object on the stack and invokes the filter block. If the exception is within the allowed three attempts the exception is handled and execution is returned to the top. *(This can also be decided based on type but this example is using the user defined filter)
Come the third failed attempt the filter clause puts a 0 back on the evaluation stack and the exception handler clause is skipped and the exception is passed to the next available handler in the call stack. There is none in this case so the exception is unhandled and the application exits. [The sample code can be downloaded from here and compiled using the ILASM tool that ships with the .NET SDK. Compiled executable here.]

[Note: A very cool IDE add-in for Visual Studio 2005 is Visual IL by available from GotDotNet by Craig Skibo].

.assembly extern mscorlib { }
.
assembly FilterRetry { }
.
module FilterRetry.exe
.
namespace Acme {
    .
class public auto ansi PasswordChecker extends [mscorlib]System.Object {
        .
method public static void check( ) cil managed 
        {            
            .locals init (int32 counter, 
string secret)
            .entrypoint
            ldstr        "secret" 
            stloc.1
        AskForPassword:
            ldstr "Enter your password:"
            
call void [mscorlib]System.Console::WriteLine(string)
            .
try // Try in scope form
            {    // Guarded code            
                
call        string [mscorlib]System.Console::ReadLine()                                
                ldloc.1
                
call        bool [mscorlib]System.String::op_Equality(string,string)
                brfalse.s   Incorrect                
                leave.s        AllowAccess
                Incorrect:
                // increment counter
                ldloc.0
                ldc.i4.1
                add
                stloc.0                
                // 
throw exception                                        
                
ldstr "You have been kicked out!"
                newobj instance void [mscorlib]System.
Exception::.ctor(string)
                
throw
            
}
            
filter
            
{    // Here we decided whether we should invoke the handler
                pop
                ldc.i4.3
                ldloc.0                
                cgt                
                endfilter
            }            
            {    // Actual handler code starts here                        
                ldstr "You have been granted another pop by the filter!"
                
call void [mscorlib]System.Console::WriteLine(string)
                leave.s AskForPassword
            }
        AllowAccess:            
            ldstr "Welcome to the AllowAccess block"        
            
call void [mscorlib]System.Console::WriteLine(string)        
            ret
        } // 
end of method
    
} // end of class
} // end of namespace

In Visual Basic.NET something similar can be achieved by doing something like the following (Just an arbitary sample, not related to the one above]:

 Sub Exception1()
        
Try
            
Console.WriteLine("Exception1")
            
Dim As Integer = 10 / z
        
Catch As OverflowException When DoIFeelLikeIt(e)
            Console.WriteLine("Caught DivideByZero")
        
Catch As Exception
            
Console.WriteLine("Some exception")
        
        
End Try
    End Sub

    Function DoIFeelLikeIt
(ByRef As ExceptionAs Boolean
        
Console.WriteLine("Filtering {0}", e.Message)
        
If DateTime.Now.Hour > 8 And DateTime.Now.Hour < 19 Then
            Return True
        End If
        Return False
    End Function

Another example of a SEH clause not available in the C# language is the fault clause. It is similar to the finally clause except that it's only invoked when an exception has been thrown in the guarded block.

0x0004 The handler will be engaged if any exception occurs. This type of EH clause is called a fault type. A fault handler is similar to a finally handler in all aspects except one: the fault handler is not engaged if no exception has been thrown within the guarded block and everything is nice and quiet. The fault handler must also end with the endfinally instruction, which for this specific purpose has been given the synonym endfault.

Another interesting bit of information I found out about the way managed exceptions is handled is that the finally clause is always invoked before the first found exception handler clause is invoked. Which makes sense if you think about it afterwards. I highly recommend reading the SEH chapter in Inside Microsoft IL Assembler to better understand exception handling in the runtime. [Sample chapter here which happens to be the chapter on SEH :)]

[Update. I see the code formatting didn't come out as planned on this theme. ]

powered by IMHO 1.3

Filed under:

Comments

# Senkwe said:

Cool stuff Armand, I've been looking for a good text on IL but Loot, Kalahari and Exclusive don't have any books that can be delivered quickly and Amazon takes way too long, where did you get your copy?

Wednesday, November 09, 2005 9:18 AM
# Armand du Plessis said:

We've got a copy here in the office :-)

Wednesday, November 09, 2005 10:38 AM
# Ernst Kuschke said:

Cool! Does Visual IL only run on .NET 2.0?

Wednesday, November 09, 2005 12:01 PM
# Armand du Plessis said:

Only 2005 yes. I did see some links to some other standalone editors when I was searching for an editor though.

Wednesday, November 09, 2005 12:13 PM
# Ayende @ Blog said:

IL Fault

Saturday, January 13, 2007 10:33 PM