C# 为什么localloc会破坏这个CIL方法?
我有以下一段简化的CIL代码。C# 为什么localloc会破坏这个CIL方法?,c#,.net,cil,invalidprogramexception,C#,.net,Cil,Invalidprogramexception,我有以下一段简化的CIL代码。 执行此CIL方法时,CLR将引发InvalidProgrameException: .method assembly hidebysig specialname rtspecialname instance void .ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<class System.Windows.Input.StylusDeviceBase&g
执行此CIL方法时,CLR将引发InvalidProgrameException:
.method assembly hidebysig specialname rtspecialname
instance void .ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<class System.Windows.Input.StylusDeviceBase> styluses) cil managed
{
.locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<class System.Windows.Input.StylusDeviceBase> V_0,
class System.Windows.Input.StylusDeviceBase V_1)
ldc.i4.8 // These instructions cause CIL to break
conv.u //
localloc //
pop //
ldarg.0
newobj instance void class [mscorlib]System.Collections.Generic.List`1<class System.Windows.Input.StylusDevice>::.ctor()
call instance void class [mscorlib]System.Collections.ObjectModel.ReadOnlyCollection`1<class System.Windows.Input.StylusDevice>::.ctor(class [mscorlib]System.Collections.Generic.IList`1<!0>)
ldarg.1
callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<class System.Windows.Input.StylusDeviceBase>::GetEnumerator()
stloc.0
.try
{
leave.s IL_0040
}
finally
{
endfinally
}
IL_0040: ret
} // end of method StylusDeviceCollection::.ctor
编辑2:
更多观察:-使用IL代码的
localloc
块,并将其移动到函数的末尾,代码运行良好-因此代码本身似乎是可以的。-将类似的IL代码粘贴到hello world测试函数中时,问题不会重现 我很困惑 我希望有办法从InvalidProgrameException获得更多信息。CLR似乎没有将确切的失败原因附加到异常对象。
我还考虑过使用CoreCLR调试构建进行调试,但不幸的是,我正在调试的程序与之不兼容……不幸的是,我似乎遇到了一个CLR错误 使用旧版JIT编译器时,一切正常:
设置COMPLUS\u useLegacyJit=1
我无法隔离可能导致此问题的特定RyuJit设置。
我遵循了本文中的建议:感谢所有帮助过我的人 后果: 在我遇到遗留JIT解决方案后的某个时候,我意识到这个问题只在将
localloc
(一个不可验证的操作码)插入从安全透明方法调用的安全关键方法时才会出现。只有在这种情况下,RyuJit才会抛出一个invalidProgrameException
,而遗留JIT不会
在我的复制过程中,我反汇编了有问题的DLL,并直接修改了函数代码,保持了安全属性的完整性-
特别是AllowPartiallyTrustedCallers
assembly属性,这解释了为什么这个问题没有通过一个单独的示例重现
可能在RyuJIT中,与遗留JIT相比,存在一些安全性强化问题,但事实上,localloc
将导致CLR在存在try-catch及其相对于localloc
的相对位置时抛出invalidProgrameException
解除屏蔽,看起来像是一个微妙的错误
在失败的DLL上运行SecAnnotate.exe()有助于揭示函数调用之间的安全问题
有关安全透明代码的详细信息:当您在ILSpy中打开编译后的DLL时,它是否显示您希望看到的代码?(可能只是在IL视图中-这可能不会反编译成C#,尽管我可能错了。)遗憾的是,我无法重现这一点。
ldarg.0
tocall
是否有必要?不清楚如何使用peverify.exe,它不喜欢localloc。如果ldarg.0在堆栈中不平衡,则调用列表的默认构造函数。只需删除它。@xxbbcc有趣,我没有想到将IL反编译回C#-很好!它实际上是反编译的,我将用反编译的代码编辑这个问题。@illdans4是的,似乎ldarg.0
是必需的-这是直接从原始代码中获取的。为完整起见,我还添加了以下函数调用和.locals
中的第二个本地调用,以使函数代码与原始函数的代码相同;已存在用于localloc
的localloc
在finally
中是不允许的,因此抖动可能会变得混乱,并且在这里完全不允许它,即使它不在块中。@Jeroemoster谢谢!我怀疑可能是这样的。。。我运行的是.NET4.6,因此将检查是否在最新的CoreCLR上复制。我注意到一个类似的bug已经被修复了,所以很有可能,这个bug也已经被修复了:我无法重新编程,也无法完全按照您看到的问题所需的所有描述进行操作。如果你把一个复制案例放在一起,我会更深入地看一看。@AndyAyers谢谢!已经有一段时间了,但我会设法整理一个重新起诉的案件
internal unsafe StylusDeviceCollection(IEnumerable<StylusDeviceBase> styluses)
{
IntPtr arg_04_0 = stackalloc byte[(UIntPtr)8];
base..ctor(new List<StylusDevice>());
IEnumerator<StylusDeviceBase> enumerator = styluses.GetEnumerator();
try
{
}
finally
{
}
}