Cum*_*yah 40 c# compiler-construction optimization il
下面是一个简单的测试夹具.它在Debug版本中成功,在Release版本中失败(VS2010,.NET4解决方案,x64):
[TestFixture]
public sealed class Test
{
[Test]
public void TestChecker()
{
var checker = new Checker();
Assert.That(checker.IsDateTime(DateTime.Now), Is.True);
}
}
public class Checker
{
public bool IsDateTime(object o)
{
return o is DateTime;
}
}
Run Code Online (Sandbox Code Playgroud)
似乎代码优化会造成一些破坏; 如果我在Release版本上禁用它,它也可以.这让我感到很困惑.下面,我使用ILDASM来反汇编构建的两个版本:
调试IL:
.method public hidebysig instance bool IsDateTime(object o) cil managed
{
// Code size 15 (0xf)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: isinst [mscorlib]System.DateTime
IL_0007: ldnull
IL_0008: cgt.un
IL_000a: stloc.0
IL_000b: br.s IL_000d
IL_000d: ldloc.0
IL_000e: ret
} // end of method Validator::IsValid
Run Code Online (Sandbox Code Playgroud)
发布IL:
.method public hidebysig instance bool IsDateTime(object o) cil managed
{
// Code size 10 (0xa)
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst [mscorlib]System.DateTime
IL_0006: ldnull
IL_0007: cgt.un
IL_0009: ret
} // end of method Validator::IsValid
Run Code Online (Sandbox Code Playgroud)
似乎存储和负载被优化了.针对早期版本的.NET框架使问题消失,但这可能只是一个侥幸.我发现这种行为有点令人不安,任何人都能解释为什么编译器认为进行产生不同可观察行为的优化是安全的吗?
提前致谢.
Eli*_*ing 20
雅各布斯坦利在这个问题中已经出现了这个错误.雅各布已经报告了这个漏洞,微软已经确认它确实是CLR JIT中的一个漏洞.微软有这样说:
此错误将在运行时的未来版本中修复.我担心现在判断它是在服务包还是下一个主要版本中还为时过早.
再次感谢您报告此问题.
您应该能够通过将以下属性添加到以下内容来解决此问题TestChecker()
:
[MethodImpl(MethodImplOptions.NoInlining)]
Run Code Online (Sandbox Code Playgroud)
Han*_*ant 15
它与C#编译器无关,IL是相同的.您在.NET 4.0抖动优化器中发现了一个错误.您可以在Visual Studio中重新编辑它.工具+选项,调试,常规,取消选中"在模块加载时抑制JIT优化"选项并运行发布构建以重新发生故障.
我还没有仔细研究它以找出错误.它看起来很奇怪,它内联方法并完全省略了拳击转换的代码.机器代码与版本2抖动生成的代码大不相同.
一个干净的解决方法并不容易,你可以通过抑制内联来实现.像这样:
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
public bool IsDateTime(object o) {
return o is DateTime;
}
Run Code Online (Sandbox Code Playgroud)
您可以在connect.microsoft.com上报告错误.如果你不想让我知道,我会照顾它.
没关系,已经完成了.它没有在VS2010 SP1附带的维护版本中修复.
这个bug已经修复,我再也无法重复了.我当前的clrjit.dll版本是2011年5月17日的4.0.30319.237.我无法确切地知道更新修复了什么.我在2011年8月5日获得了一个安全更新,它将clrjit.dll更新为版本235,日期为4月12日,这将是最早的.
就流量控制而言,存储和加载基本上是一个nop,但可能以某种方式按下一些CPU缓存.实际流程只是在堆栈上加载参数,检查它是否是一个实例(返回null或实例),将null推送到堆栈,并比较(大于)导致堆栈中保留的布尔值.
现在JITter用它做的是另一个故事(并且取决于你正在使用的平台.JITter将以性能的名义做各种疯狂的事情(我们的团队最近受到了打击,因为尾部调用优化改为优化跨越域边界打破了GetCallingAssembly()).JITter可能正在内联IsDateTime,注意到它不可能不是一个DateTime而只是将true推入堆栈.
您的发布版本也可能针对稍微不同的Framework,因此测试程序集中的DateTime不是测试程序集中的DateTime.
我意识到这并没有回答为什么你的代码破坏了.