Изменение кода IL, вызывающее исключение InvalidProgramException во время выполнения - PullRequest
0 голосов
/ 11 июня 2018

Я пытаюсь удалить подписку на событие 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 Ответ

0 голосов
/ 11 июня 2018

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

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

someTimer.Tick += target.SomeMethod;

это:

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

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

...