Home > .NET > Quirks in .NET – Part 1 Call vs Callvirt

Quirks in .NET – Part 1 Call vs Callvirt

Debugger Friend or Foe?

February 18th | 2010

Quirks in .NET Part -1 Call vs Callvirt

There are a lot of cool yet strange things in the .NET Framework. A lot of them make you go, “Huh. I didn’t know that.” Let’s take a look at a few of them.

call vs. callvirt

This one is especially interesting to me. In the Microsoft IL specification there are two instructions to call a method, put simply—call and callvirt. call will simply call a method, while callvirt is used to a late-bound method call, meaning that the method which is going to be called is chosen at runtime and not compile time as the simple call would. This is needed for virtual methods when a VTable lookup is required.

Interestingly, all calls to instance classes are compiled as callvirt, even if the method being called is not virtual (thus at compile time we know exactly which method will be called.) I thought it was a bug at first, but really it was a fix for another bug. Consider this code:

class Program
{
    static void Main()
    {
        HelloWorld instance = null;
        instance.SayHello();
    }
}

public class HelloWorld
{
    public void SayHello()
    {
        System.Console.WriteLine("Hello World!");
    }
}

Looks like it would immediately blow up, right? We should get a NullReferenceException. And in fact, if we compile this with the C# compiler, we do! Let’s look at the IL for the Main() method.

  L_0000: nop
  L_0001: ldnull
  L_0002: stloc.0
  L_0003: ldloc.0
  L_0004: callvirt instance void HelloWorld::SayHello()
  L_0009: nop
  L_000a: ret

Sure enough, it uses a callvirt, but here’s the interesting part: If the compiler used a call, rather than callvirt, this code would actually run. In fact, we can do that, too. Let’s change the callvirt to a call, recompile the IL using ilasm, and see what happens.

netquirks

Yeah, it appears that our program, which should be causing a NullReferenceException, isn’t. This is why the .NET compilers don’t use call, even though using call is a perfectly acceptable in this case. For that matter, the only time a regular call will be used is when you call a method on a struct, or a static method on a class.

If you use the Reflection.Emit namespace frequently, or are looking into it, this is something to watch out for.

In Quirks in .Net  Part 2. we’ll look at Marshalling Booleans.

Kevin Jones is a Team Lead at Thycotic Software, an agile software services and product development company based in Washington DC. Secret Server is our flagship password management software product. On Twitter? Follow Kevin

Categories: .NET
  1. Richard
    March 1, 2010 at 2:32 pm

    “callvirt is used to a late-bound method call”

    Not quite – there’s a huge difference between a virtual method call and a late-bound method call.

  2. Kevin
    March 10, 2010 at 10:36 am

    Richard,

    Speaking in general terminology “Late Bound” can mean a lot of things. Late bound resolution can mean resolving which method is invoked as part of a VTable lookup. Take for example the definition of “Dynamic Binding”

    http://en.wikipedia.org/wiki/Dynamic_binding_(computer_science)

  1. February 25, 2010 at 10:29 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: