CathalMF
CathalMF

Reputation: 10055

Modifying IL code causing InvalidProgramException at runtime

Im trying to remove the subscription to the Tick event in IL Code so that it wont ever fire.

Here is the IL Code:

IL_0e19:  ldftn      instance void App.Framework.MainForm::mTimer_Tick(object, class [mscorlib]System.EventArgs)
IL_0e1f:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object, native int)
IL_0e24:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Timer::add_Tick(class [mscorlib]System.EventHandler)
IL_0e29:  ldarg.0

So i was thinking i should just be able to remove the last 2 lines to remove the subscription and it should be fine.

IL_0e24:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Timer::add_Tick(class [mscorlib]System.EventHandler)
IL_0e29:  ldarg.0

I compile the IL code successfully with:

ilasm.exe c:\Framework.il /32bitpreferred /dll

Now when i try and launch the program it throws the exception:

System.InvalidProgramException: JIT Compiler encountered an internal limitation.

If i compile the IL without any modifications then the program runs without any exceptions, so its the changes im making.

Upvotes: 3

Views: 486

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062780

The ldarg0 is unrelated and presumably relates to the next operation; so you shouldn't be dropping that. You've also left something on the stack, so instead of just removing the callvirt, you should instead be popping two values - the target instance (load not shown) and the event handler instance (from the ldftn/newobj - note there's also a load not shown that relates to this step). Or alternatively - don't load those two values in the first place. There's presumably quite a bit of stuff happening before IL_0e19 that could do with some cleanup.

Basically, given code like:

someTimer.Tick += target.SomeMethod;

this is:

  • load someTimer [stack now someTimer]
  • load target [stack now someTimer, target]
  • load SomeMethod as a function pointer [stack now someTimer, target, function pointer]
  • create a delegate for that object/pointer [stack now someTimer, delegate]
  • virtual-call the Tick_add method [stack now empty]

The IL you have show starts at "load SomeMethod as a function pointer", and includes an unrelated load for the next operation.

Upvotes: 4

Related Questions