Mono.Cecil - can't import constructors

497 views Asked by At

I've injected an empty method into a class. I'm now trying to fill it with this simple following code:

Affliction test = new Affliction ();
if (test != null)
    Console.AddMessage ("not null");

I've converted this snippet into ILCode with Reflexil and it works fine when I inject it with Reflexil itself.

However, when I inject the same ilcode instructions with Cecil, I get an error when running the program and I also can't open it in .Net Reflector. This is the ILcode that I'm injecting:

IL_0000: newobj System.Void Affliction::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldnull
IL_0008: call System.Boolean Affliction::op_Inequality(Affliction,Affliction)
IL_0013: brfalse.s IL_0025
IL_0015: ldstr "not null"
IL_0020: call System.Void Console:AddMessage(System.String)
IL_0025: ret

This is how I do it:

System.Reflection.ConstructorInfo constrInfo = typeof(Affliction).GetConstructors()[0];
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Newobj, mainMod.Import (constrInfo)));
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Stloc_0));
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_0));
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Call, mainMod.Import(typeof(Affliction).GetMethod ("op_Inequality"))));
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse_S, newMethod.Body.Instructions[1])); // instruction reference will be changed later
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, "not null"));
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Call, mainMod.Import(typeof(Console).GetMethod("AddMessage", new Type[]{typeof(String)}))));
newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
newMethod.Body.Instructions [5].Operand = newMethod.Body.Instructions [8];

The inspection of the resulting instructions shows exactly what I'm aiming for. And yet they don't work.

Here's the error I get in the program: InvalidProgramException: Invalid IL code in CommandLine:TestCecil (): IL_0005: stloc.0

And .Net Reflector throws an error saying Index was outside the bounds of the array.

This makes me think that the first instruction Newobj for some reason can't create an object and doesn't push the reference onto the evaluation stack. Then, the next instruction stloc.0 can't pop it and put it into the list of local variables, and this throws errors. When I reference normal methods in the same way, they are called just fine, but the constructors produce errors. What did I miss?

1

There are 1 answers

0
Glabrezu On BEST ANSWER

Jb Evain answered the question on the Google Group, so I'll just leave his answer here in case somebody else has this problem.

Hi,

I think you're just missing one thing: you're not creating the variable.

You need to add a VariableDefinition to newMethod.Body.Variables. Otherwise stloc.0 has no variable at index 0.