Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling instance method on a null reference in IL

Tags:

c#

null

cil

Is it correct that a instance method can be called on a null reference in IL..? Is there any example to show this..?

like image 302
Santhosh Avatar asked Aug 10 '10 10:08

Santhosh


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:

Instance Methods Called on null References

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.

like image 81
Dirk Vollmar Avatar answered Sep 28 '22 01:09

Dirk Vollmar


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
  }
}
like image 31
leppie Avatar answered Sep 28 '22 00:09

leppie


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;
}
like image 22
Hans Passant Avatar answered Sep 28 '22 02:09

Hans Passant