This question is about static analysis of stacks of custom C # IL code and how to create opcodes to satisfy the compiler.
I have code that modifies existing C # methods by adding my own code to it. To avoid the original method, return to my code, it replaces all the code RET symbol BR endlabel and adds this mark the end of the source code. Then I add more code and finally RET.
Everything works fine, but it doesnβt work on certain methods. Here is a simple example:
public static string SomeMethod(int val)
{
switch (val)
{
case 0:
return "string1".convert();
case 1:
return "string2".convert();
case 2:
return "string3".convert();
}
return "";
}
which is represented by this IL code:
.method public hidebysig static string SomeMethod(int32 val) cil managed
{
.maxstack 1
.locals val ([0] int32 num)
L_0000: ldarg.0
L_0001: stloc.0
L_0002: ldloc.0
L_0003: switch (L_002e, L_004f, L_0044, ...)
L_002c: br.s L_0091
L_002e: ldstr "string1"
L_0033: call string Foo::convert(string)
L_0038: ret
L_0039: ldstr "string2"
L_003e: call string Foo::convert(string)
L_0043: ret
L_0044: ldstr "string3"
L_0049: call string Foo::convert(string)
L_004e: ret
...
L_0091: ldstr ""
L_0096: ret
}
After changing my program, the code looks like this:
.method public hidebysig static string SomeMethod(int32 val) cil managed
{
.maxstack 1
.locals val ([0] int32 num)
L_0000: ldarg.0
L_0001: stloc.0
L_0002: ldloc.0
L_0003: switch (L_002e, L_004f, L_0044, ...)
L_002c: br.s L_0091
L_002e: ldstr "string1"
L_0033: call string Foo::convert(string)
L_0038: br L_009b // was ret
L_0039: ldstr "string2"
L_003e: call string Foo::convert(string)
L_0043: br L_009b // was ret
L_0044: ldstr "string3"
L_0049: call string Foo::convert(string)
L_004e: br L_009b // was ret
...
L_0091: ldstr ""
L_0096: br L_009b // was ret
L_009b: my code here
...
L_0200: ret
}
and I get a compilation error:
post-long-event. : System.TypeInitializationException: FooBar --- > System.InvalidProgramException: IL ( -) Foo: SomeMethod (int): IL_0000: ldnull
RET ?