IL perversions: throwing and catching strings

Inspired by Mohamed Mahmoud’s blog posting How to: Create Interfaces with Static Methods via IL? I wrote another sick example on IL (Intermediate Language) to show you how different is the world behind compilers. For tonight I have enough of exceptions, I want to throw some strings! Let’s do it!

Sample solution available! I made sample solution for this blog post available at GitHub repository gpeipman/ThrowStrings. GitHub page has also links to all necessary tools and support materials that help you to make solution work on your machine.

Throwing exception in IL

As a first thing take a look at the following code written in IL. In short this code defines class with two methods. Run() is entry point and it is run automatically when compiled assembly is executed from command line. ThrowSomething() is method that throws exception. This exception is caught and program terminates without any errors. I borrowed this code from Vijay Mukhi’s IL book, Chapter 10 “Exception Handling”.


.assembly StringMess {}
.
class private auto ansi Program extends [mscorlib]System
.Object
{
    .method
public hidebysig static void
Run() il managed
    {
        .entrypoint
        .locals (
class [mscorlib]System
.Exception V_0)
        .
try
        {
            call   
void
Program::ThrowSomething()
            ldstr  
"Bye"
            call    void [mscorlib]System
.Console::WriteLine
                    (
class System
.String)
            leave.s IL_001e
        }
       
catch [mscorlib]System
.Exception
        {
            stloc.0
            ldstr  
"Exception was thrown!"
            call    void [mscorlib]System
.Console::WriteLine
                    (
class System
.String)
            leave.s IL_001e
        }
 
        IL_001e: ldstr
"Finish"
        call     void [mscorlib]System
.Console::WriteLine
                 (
class System
.String)
        ret
    }
 
    .method
public hidebysig static void
ThrowSomething()
        il managed
    {
        newobj instance
void [mscorlib]System
.Exception::.ctor()
       
throw
    }
}

Exception was thrown in ILEverybody who is familiar with C# should be able to understand this code at least in some parts. Now let’s see what is the output of this method. As image on right shows it is nothing special. We threw exception, it was handled and program terminated normally. Just like we expected.

Let’s throw some strings now

Now let’s modify this code so it should do something we expect to end up with error. I add one more catch clause. This additional catch catches String. To test it I will do exactly what this catch expects – I will throw out the String. Here is the code.


.assembly StringMess {}
.
class private auto ansi Program extends [mscorlib]System
.Object
{
    .method
public hidebysig static void
Run() il managed
    {
        .entrypoint
        .locals (
class [mscorlib]System
.Exception V_0)
        .
try
        {
            call   
void
Program::ThrowSomething()
            ldstr  
"Bye"
            call    void [mscorlib]System
.Console::WriteLine
                    (
class System
.String)
            leave.s IL_001e
        }
       
catch [mscorlib]System
.Exception
        {
            stloc.0
            ldstr  
"Exception was thrown!"
            call    void [mscorlib]System
.Console::WriteLine
                    (
class System
.String)
            leave.s IL_001e
        }
       
//
        // CATCH STRING
        //
        catch
System.String
        {
            stloc.0
            ldstr   
"String was thrown"
            call    void [mscorlib]System
.Console::WriteLine
                    (
class System
.String)
            leave.s IL_001e
        }
 
        IL_001e: ldstr
"Finish"
        call     void [mscorlib]System
.Console::WriteLine
                      (
class System
.String)
        ret
    }
 
    .method
public hidebysig static void
ThrowSomething()
        il managed
    {
       
//newobj instance void [mscorlib]System.Exception::.ctor()
        //
        // THROW STRING
        //
        ldsfld     string [mscorlib]System
.String::Empty      
       
throw
    }
}

We can expect that this code doesn’t compile, but it does. As a next thing we may expect that running this code some runtime error occurs, but no, there is no runtime error. We can expect that exception handling lands in catch for Exception… we can expect many things but the result is here.

String was thrown in ILI bet at least half of readers expected something else but yes, we just threw string and we also caught it. But why C# and VB.NET give us errors when we try to compile code like this? Well, it is a compiler level limitation. It is not related to CLR as we just saw.

Playing with Visual Studio

Let’s play now with Visual Studio. I created console application, compiled previous example as DLL and referenced it from my console application. I want to know what happens when string is thrown and caught. Does it affect compiler somehow?


using System;
 

namespace
ConsoleExamples
{
   
class Program
    {
       
static void Main(string
[] args)
        {
            StringMess.Program.Run();
           
Console
.ReadLine();
           
Console.ReadLine();
        }
    }
}

Well, it does not. Let’s try to call ThrowSomething() method now. Maybe something interesting happens.


using System;
 

namespace
ConsoleExamples
{
   
class Program
    {
       
static void Main(string
[] args)
        {
            StringMess.Program.ThrowSomething();
           
Console.ReadLine();
        }
    }
}

Okay, now something happens. Our application is not able to handle the situation and it throws RuntimeWrappedException.

RuntimeWrappedException was throw instead of string

RuntimeWrappedException is located under System.Runtime.CompilerServices namespace and as documentation sais it is here to maintain compatibility between languages. The common language runtime (CLR) wraps objects that do not derive from Exception in a RuntimeWrappedException object. This is why we got exception and not completely crashed application.

TIP! If you want to find out more about IL there is very good book I can suggest: Expert .NET 2.0 IL Assembler by Serge Lidin. I have read this book and also the idea of this posting is taken from this book. If you are interested in my other postings about IL and compiling results then please take a look at IL category.

Okay, it’s couple of minutes over midnight here and it is time to throw some real strings, I guess. Good night!

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.