如果语句似乎正在评估,即使条件评估为false

por*_*ges 12 .net c# x86 assembly .net-assembly

昨晚工作到很晚,我们试图找出原因失败的原因.验证检查在不应该的时候失败了.

我们最终在这段代码中添加了一个print语句(从Reflector中反汇编,以便检查代码实际上是我们编写的代码):

public static string Redacted(string name, DateTime lastModified)
{
    long ticks = lastModified.Ticks;
    if ((ticks != (ticks - (ticks % 10000L))) &&
            (lastModified != DateTime.MaxValue))
    {
        Log.Debug(string.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'",
            lastModified.ToString("dd/MM/yyyy hh:mm:ss.fff"),
            ticks, ticks - (ticks % 10000L)));
Run Code Online (Sandbox Code Playgroud)

它打印(重新格式化):

Last Modified Date = '22/03/2011 12:16:22.000'.
Ticks     = '634363497820000000'.
TicksCalc = '634363497820000000'            
Run Code Online (Sandbox Code Playgroud)

但条件是" ticks"(等于上面打印的Ticks)不等于" (ticks - (ticks % 10000))"(等于TicksCalc)!634363497820000000!= 634363497820000000?!

为了确定这里发生了什么,我们又添加了两个语句:

long ticks = lastModified.Ticks;
/* Added following two lines: */
long num2 = ticks - (ticks % 10000L);
Log.Debug((ticks == num2).ToString());
/* */
if ((ticks != (ticks - (ticks % 10000L))) &&
        (lastModified != DateTime.MaxValue))
{
    Log.Debug(string.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'",
        lastModified.ToString("dd/MM/yyyy hh:mm:ss.fff"),
        ticks, ticks - (ticks % 10000L)));
Run Code Online (Sandbox Code Playgroud)

应该有,这个打印true(当测试时具有相同的值),并没有写第二行.

感觉有点迷失,我们再次删除了两行,重新编译,并重新.原来的行为重演了.

今天早上,我录制了一段视频.

首先,视频显示使用"损坏"代码在方法中命中断点,然后使用"工作"代码重建和重新运行.请注意,即使调试器显示if条件的计算结果false,仍然会输入正文.

我已经看到这样的事情发生在调试器观察之前,因为调试器强制要求评估一些事情,但无论是否使用调试器都会发生这种情况.

此外,这仅在发布模式下发生(即启用了JIT优化).

以下是两个版本的反汇编方法:工作,不工作.我不能真正阅读汇编,所以我将它们发布在这里是为了澄清.

我希望答案不是我完全忽略的明显的答案......!

编辑:这是IL.我认为它没有任何问题,因为它反编译为正确的C#:

更新:

被Microsoft确认为bug,将在下一版本中修复.

Cod*_*aos 9

我用简化的代码进行了一些实验:http: //nopaste.info/2c99a0e028_nl.html

最有趣的变化是:

static readonly long variableZero=0; 
const long constZero=0; 

public static void Broken2( long ticks2) 
 { 
     long ticks = ticks2+variableZero; 
     if (ticks != (ticks - (ticks % 10000L))) 
     { 
         string.Format("Last Modified Date = '{0}'. Ticks = '{1}'. TicksCalc = '{2}'", 
             "n/A", 
             ticks, ticks - (ticks % 10000L)).Dump(); 
     } 
 }
Run Code Online (Sandbox Code Playgroud)

如果我更换variableZeroconstantZero它的工作原理.


所以我很确定它是一个抖动或编译器错误.

我在MS Connect上提交了一个bug报告:https: //connect.microsoft.com/VisualStudio/feedback/details/671105/jitter-or-c-compiler-bug#details


更新:仅在未附加调试器时才会出现奇怪的行为.即启用Jit优化时.所以我很确定这是一个抖动错误.

对于没有linq-pad的人来说,现在有一个简单的C#控制台项目:http://nopaste.info/00a0e37328_nl.html