Is it correct that a instance method can be called on a null reference in IL..? Is there any example to show this..?
-
Surely this isn't possible - what instance would you execute the method on? – Adam Houldsworth Aug 10 '10 at 10:28
-
2@Adam: it is very possible with a bit of IL hackery. The code is still 100% verifiable, but the C# compiler would never emit such code. – leppie Aug 10 '10 at 10:41
-
Fair enough, how does it get from the null reference and redirect to the correct instance in memory? For example, if the method modified internal state. – Adam Houldsworth Aug 10 '10 at 13:22
-
@Adam: Of course, this only works if the method doesn't access any of the object's fields as mentioned in Hans' and my answer. – Dirk Vollmar Aug 10 '10 at 14:04
3 Answers
Yes, this is possible, as long as the method doesn't use this
because the CLR does not do a null check for call
instructions.
You would have to modify the IL by hand as the C# compiler would almost always generate a callvirt
instruction1.
See this blog post for details and an example:
Sample
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 18 (0x12)
.maxstack 1
.locals init ([0] class SomeClass o, [1] string hello)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: call instance string SomeClass::GetHello()
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: call void [mscorlib]System.Console::WriteLine(string)
IL_0010: nop
IL_0011: ret
}
1In fact the reason that the C# compiler emits callvirt
even in cases where a simple call
instruction would be sufficient is to prevent calling instance methods on null references. With this behavior of the compiler users will get a NullReferenceException
so the weird situation of calling a method on a null pointer is avoided. Eric Gunnerson explained this in a blog post some time ago: Why does C# always use callvirt? Gishu also has a nice explanation in a related question.

- 21,988
- 13
- 81
- 109

- 172,527
- 53
- 255
- 316
See my blog entry for info.
IL code sample:
.class Program
{
.method static void Main(string[] args)
{
.entrypoint
.locals init ([0] class Program p)
ldloc.0 // but wait, it's still null!
call instance void Program::Awesome()
ret
}
.method instance void Awesome()
{
ldstr "Awesome!"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
.method public specialname rtspecialname instance void .ctor()
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}

- 115,091
- 17
- 196
- 297
The CLR doesn't require it, it is an implementation detail of the language. C# and VB.NET perform the test. C++/CLI is a notable managed language that permits it. As long as the instance method doesn't reference any class members then nothing goes wrong. If is does, NullReferenceException will be raised as normal, merely giving you a hard time finding out why.
#include "stdafx.h"
using namespace System;
ref class Test {
public:
void Run() {
Console::WriteLine("no problem");
}
};
int main(array<System::String ^> ^args)
{
Test^ obj = nullptr;
obj->Run();
return 0;
}

- 922,412
- 146
- 1,693
- 2,536