2010-08-10 6 views
6

Est-il correct qu'une méthode d'instance puisse être appelée sur une référence nulle dans IL ..? Existe-t-il un exemple pour illustrer cela?Méthode d'instance d'appel sur une référence nulle dans IL

+0

Certainement pas possible - sur quelle instance exécuteriez-vous la méthode? –

+2

@Adam: c'est très possible avec un peu de hackery IL. Le code est toujours vérifiable à 100%, mais le compilateur C# n'émettrait jamais un tel code. – leppie

+0

Assez juste, comment obtient-il de la référence nulle et redirige vers l'instance correcte dans la mémoire? Par exemple, si la méthode a modifié l'état interne. –

Répondre

10

Oui, cela est possible, tant que la méthode n'utilise pas this car le CLR ne vérifie pas les instructions call.

Vous auriez à modifier l'IL à la main car le compilateur C# générerait presque toujours une instruction callvirt .

Voir ce billet de blog pour plus de détails et un exemple:

Instance Methods Called on null References

Exemple

.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 
} 

En fait, la raison pour laquelle le compilateur C# émet callvirt même dans les cas où une simple instruction call suffirait à empêcher l'appel de méthodes d'instance sur des références nulles. Avec ce comportement du compilateur, les utilisateurs obtiendront un NullReferenceException donc la situation étrange d'appeler une méthode sur un pointeur nul est évitée. Eric Gunnerson a expliqué cela dans un billet de blog il y a quelque temps: Why does C# always use callvirt?Gishu a également une bonne explication dans un related question.

5

Voir mes blog entry pour info.

exemple IL code:

.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 
    } 
} 
3

Le CLR ne nécessite pas, il est un détail de la mise en œuvre de la langue. C# et VB.NET effectuent le test. C++/CLI est un langage managé notable qui le permet. Tant que la méthode d'instance ne référence aucun membre de la classe, rien ne se passe mal. Si c'est le cas, NullReferenceException sera levé comme d'habitude, vous donnant simplement du mal à trouver pourquoi.

#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; 
}