问题描述
昨晚工作到很晚,我们试图弄清楚为什么有些事情失败了.验证检查在不应该失败的情况下失败了.
Late At Work last night, we were trying to figure out why something was failing. A validation check was failing when it shouldn't have been.
我们最终在此代码中添加了一条打印语句(从 Reflector 中反汇编以检查代码是否确实是我们所写的):
We ended up adding a print statement to this code (disassembled from Reflector in order to check that the code was actually what we had written):
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)));
它打印(重新格式化):
It printed (reformatted):
Last Modified Date = '22/03/2011 12:16:22.000'.
Ticks = '634363497820000000'.
TicksCalc = '634363497820000000'
但条件是ticks
"(等于上面打印的Ticks)不等于(ticks - (ticks % 10000))
"(等于 TicksCalc)!634363497820000000 != 634363497820000000?!
But the condition is that "ticks
" (which is equal to Ticks printed above) is not equal to "(ticks - (ticks % 10000))
" (which is equal to TicksCalc)! 634363497820000000 != 634363497820000000?!
为了确定这里发生了什么,我们添加了另外两个语句:
In order to determine what is going on here, we added another two statements:
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)));
它应该有,这个打印了true
(用相同的值测试时),没有写第二行.
As it should have, this one printed true
(when testing with the same value), and didn't write the second line.
感觉有点迷茫,我们又把这两行删了,重新编译,重新运行.原来的行为重复了.
Feeling a bit lost, we then removed the two lines again, recompiled, and reran. The original behaviour repeated itself.
今天早上,我录制了一个视频.
视频首先展示了使用损坏"代码在方法中遇到断点,然后使用工作"代码重建和重新运行.请注意,即使调试器显示 if
条件的计算结果为 false
,仍会输入正文.
The video first of all shows hitting a breakpoint in the method using the 'broken' code, then rebuilding and rerunning using the 'working' code. Note that even though the debugger displays that the if
condition evaluates as to false
, the body is still entered.
我以前在调试器观察时看到过这样的事情发生,因为调试器强制对某些东西进行评估,但无论是否使用调试器都会发生这种情况.
I've seen things like this happen before when observed by the debugger, due to the debugger forcing some things to be evaluated, but this happens whether or not the debugger is employed.
此外,这只发生在发布模式下(即启用 JIT 优化).
Furthermore, this only happens in Release mode (i.e. with JIT optimizations enabled).
以下是两个版本的反汇编方法:working、不工作.我真的看不懂汇编,所以我把它们贴在这里希望能得到说明.
Here are the disassembled methods for both versions: working, not working. I can't really read assembly, so am posting them here in the hopes of elucidation.
我希望答案不是我完全忽略的显而易见的东西......!
I hope that the answer isn't something obvious that I've overlooked completely...!
这是IL.我不认为它有什么问题,因为它反编译为正确的 C#:
Here is the IL. I don't think there's anything wrong with it because it decompiles to the correct C#:
更新:
推荐答案
我尝试了一些简化的代码:http://nopaste.info/2c99a0e028_nl.html
I experimented a bit with simplified code: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();
}
}
如果我用 constantZero
替换 variableZero
就可以了.
If I replace variableZero
with constantZero
it works.
所以我很确定这是抖动或编译器错误.
So I'm pretty sure it is either a jitter or a compiler bug.
我已在 MS Connect 上提交了错误报告:https://connect.microsoft.com/VisualStudio/feedback/details/671105/jitter-or-c-compiler-bug#details
I've filed a bugreport on MS Connect:https://connect.microsoft.com/VisualStudio/feedback/details/671105/jitter-or-c-compiler-bug#details
更新:只有在没有附加调试器时才会出现这种奇怪的行为.即启用 Jit 优化时.所以我很确定这是一个抖动错误.
Update: The strange behavior only occurs if no debugger is attached. i.e. when Jit optimization is enabled. So I'm pretty sure it's a jitter bug.
对于没有 linq-pad 的人来说,现在有一个普通的 C# 控制台项目:http://nopaste.info/00a0e37328_nl.html一个>
And for people without linq-pad there is now a plain C# console project: http://nopaste.info/00a0e37328_nl.html
这篇关于即使条件评估为假,If 语句似乎也在评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!