Изменение кода IL, вызывающее исключение InvalidProgramException во время выполнения

Я пытаюсь удалить подписку на событие Tick в IL Code, чтобы оно никогда не срабатывало.

Вот код IL:

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

Так что я подумал, что я должен иметь возможность удалить последние 2 строки, чтобы удалить подписку, и все должно быть в порядке.

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

Я успешно компилирую код IL с помощью:

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

Теперь, когда я пытаюсь запустить программу, она выдает исключение:

System.InvalidProgramException: JIT Compiler encountered an internal limitation.

Если я скомпилирую IL без каких-либо модификаций, то программа запускается без каких-либо исключений, поэтому изменения вносятся.

1 ответ

ldarg0 не связан и предположительно относится к следующей операции; так что вы не должны бросать это. Вы также оставили что-то в стеке, поэтому вместо того, чтобы просто удалить callvirt, вы должны вместо этого вывести два значения - целевой экземпляр (загрузка не показана) и экземпляр обработчика события (из ldftn / newobj - обратите внимание, что есть также не показанная загрузка, которая относится к этому шагу). Или в качестве альтернативы - не загружайте эти два значения в первую очередь. Вероятно, довольно много вещей происходит раньше IL_0e19 это может сделать с некоторой очисткой.

В основном, такой код:

someTimer.Tick += target.SomeMethod;

это:

  • загрузить someTimer [стек теперь someTimer]
  • загрузить цель [стек теперь someTimer, цель]
  • загрузить SomeMethod в качестве указателя на функцию [стек теперь someTimer, target, указатель на функцию]
  • создать делегата для этого объекта / указателя [стек теперь someTimer, делегат]
  • виртуальный вызов метода Tick_add [стек теперь пуст]

IL, который вы показываете, начинается с "загрузить SomeMethod как указатель на функцию" и включает несвязанную загрузку для следующей операции.

Другие вопросы по тегам