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
Répondre
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:
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.
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
}
}
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;
}
Certainement pas possible - sur quelle instance exécuteriez-vous la méthode? –
@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
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. –