c# - 在运行时修改导致 InvalidProgramException 的 IL 代码
问题描述
我试图在 IL 代码中删除对 Tick 事件的订阅,以便它永远不会触发。
这是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
所以我在想我应该能够删除最后两行来删除订阅,它应该没问题。
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,那么程序将毫无例外地运行,因此我正在做出更改。
解决方案
是无关的ldarg0
,可能与下一个操作有关;所以你不应该放弃它。您还在堆栈上留下了一些东西,因此您不应仅删除callvirt,而应弹出两个值 - 目标实例(未显示加载)和事件处理程序实例(来自ldftn
/ newobj
- 注意还有一个加载不显示与此步骤有关)。或者 - 首先不要加载这两个值。在此之前可能会发生很多事情IL_0e19
,可以进行一些清理。
基本上,给定的代码如下:
someTimer.Tick += target.SomeMethod;
这是:
- 加载 someTimer [现在堆栈 someTimer]
- 加载目标 [stack now someTimer, target]
- 将 SomeMethod 作为函数指针加载 [现在堆栈 someTimer、目标、函数指针]
- 为该对象/指针创建一个委托 [stack now someTimer, delegate]
- 虚拟调用 Tick_add 方法 [堆栈现在为空]
您展示的 IL 以“将 SomeMethod 作为函数指针加载”开始,并包含下一个操作的无关加载。
推荐阅读
- reactjs - 如何使用 react-data-table-component 显示存储在构造函数 this:state 中的数组?
- java - 关于 3rd-party jar 包占用的内存空间
- python - 在数据框中对值进行平方时保留符号
- algorithm - 以最小的差异对数组进行分区
- android-intent - 如何在 RecyclyrView 的适配器内对浏览器进行 Intent
- linux-device-driver - 为什么linux驱动程序同时使用信号量和spin_lock?
- java - 使用 drop table tablename cascade 删除的依赖对象列表
- c# - 文本框不显示文本和 UI 屏幕不移动
- html - CSS 将子 div 置于中心位置
- python - 如何格式化随机抽样的列表元素?