这个问题需要一些介绍.
我正在开发一个安全项目,它将分析CIL程序集并拒绝那些执行某些定义的"坏"事情,同时还允许托管应用程序为某些方法提供"门",以允许某些调用被过滤.(这是项目功能的一小部分,但这是我将在这里查询的部分.)
该项目扫描程序集中每个方法中的所有指令,并查找调用,callvirt,ldftn,ldvirtftn和newobj操作码,因为这些是唯一可以最终导致方法调用的操作码.构造委托时使用ldftn操作码,如下所示:
ldarg.1
ldftn instance bool string::EndsWith(string)
newobj instance void class [System.Core]System.Func`2<string, bool>::'.ctor'(object, native int)
Run Code Online (Sandbox Code Playgroud)
在此序列结束时,a Func<string, bool>位于堆栈的顶部.
假设我想拦截所有来电String.EndsWith(String).对于call和callvirt,我可以用签名的静态调用替换实例调用Boolean(String,String)- 第一个参数将是最初调用该方法的字符串实例.在CIL级别上,行为将是明确且明确定义的,因为这是静态方法的调用方式.
但对于ldftn?我尝试用替换call/callvirt的操作数的相同静态方法替换ldftn指令的操作数:
ldarg.1
ldftn bool class Prototype.Program::EndsWithGate(string, string)
newobj instance void class [System.Core]System.Func`2<string, bool>::'.ctor'(object, native int)
Run Code Online (Sandbox Code Playgroud)
我完全期望这会失败,因为委托给了一个目标对象(不是null),同时传递一个静态方法指针.令我惊讶的是,这实际上适用于Microsoft .NET运行时和Mono.我知道target/this参数只是方法的第一个参数,并且对于实例方法是隐藏的.(该项目基于这些知识.)但是代表们在这种情况下实际工作的事实对我来说有点令人费解.
所以,我的问题是:这是定义和记录的行为吗?代理在被调用时是否总是将目标压缩到堆栈上,如果它不是空的?构建一个捕获目标并"正确"调用静态方法的闭包类会更好吗,即使这会更复杂和烦人吗?
ECMA 335规范第2部分14.6.2有一个关于此的段落:T和D的调用约定应完全匹配,忽略静态和实例方法之间的区别.(即如果有这个参数,则不予特别处理).
这对我来说听起来像静态方法的内容将有两种变体:
| 归档时间: |
|
| 查看次数: |
319 次 |
| 最近记录: |