错误只发生在编译优化启用

我遇到了代码中的一个错误,只有在代码是在启用优化的情况下才会生成。 我制作了一个控制台应用程序,用于复制testing逻辑(下面的代码)。 你会看到,启用优化时,在执行这个无效逻辑之后,“value”变为null:

if ((value == null || value == new string[0]) == false) 

修复很简单,在违规代码下面注释掉。 但是……我更担心的是,我可能碰到过汇编程序中的一个错误,或者其他人可能会解释为什么value被设置为null。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace memory_testing { class Program { sta tic void Main(string[] args) { while(true) { Console.Write("Press any key to start..."); Console.ReadKey(); Console.WriteLine(); PrintManagerUser c = new PrintManagerUser(); c.MyProperty = new string[1]; } } } public class PrintManager { public void Print(string key, object value) { Console.WriteLine("Key is: " + key); Console.WriteLine("Value is: " + value); } } public class PrintManagerUser { public string[] MyProperty { get { return new string[100]; } set { Console.WriteLine("Pre-check Value is: " + value); if ((value == null || value == new string[0]) == false) { Console.WriteLine("Post-check Value is: " + value); new PrintManager().Print("blah", value); } //if (value != null && value.Length > 0) //{ // new PrintManager().Print("blah", value); //} } } } } 

正常的输出应该是:

 Pre-check Value is: System.String[] Post-check Value is: System.String[] Key is: blah Value is: System.String[] 

越野车输出是:

 Pre-check Value is: System.String[] Post-check Value is: Key is: blah Value is: 

我的环境是运行Windows Server 2003 R2与.NET 3.5 SP1的虚拟机。 使用VS2008团队系统。

谢谢,

布赖恩

是的,你的表情会令JIT优化器非常混乱。 生成的机器代码如下所示:

  if ((value == null || value == new string[0]) == false) 00000027 test esi,esi ; value == null? 00000029 je 00000075 0000002b xor edx,edx ; new string[0] 0000002d mov ecx,6D913BD2h 00000032 call FFD20BC8 00000037 cmp eax,esi ; (value == new string[0]) == false? 00000039 je 00000075 { Console.WriteLine("Post-check Value is: " + value); 0000003b mov ecx,dword ptr ds:[03532090h] ; "Post-check value is: " 00000041 xor edx,edx ; BUGBUG not null! 00000043 call 6D70B7E8 ; String.Concat() 00000048 mov esi,eax ; 0000004a call 6D72BE08 ; get Console.Out 0000004f mov ecx,eax 00000051 mov edx,esi 00000053 mov eax,dword ptr [ecx] 00000055 call dword ptr [eax+000000D8h] ; Console.WriteLine() 

该错误发生在地址41,优化器得出的结论是,值将始终为空,因此它直接将null传递给String.Concat()。

作为比较,这是JIT优化closures时生成的代码:

  Console.WriteLine("Post-check Value is: " + value); 00000056 mov ecx,dword ptr ds:[03342090h] 0000005c mov edx,dword ptr [ebp-8] 0000005f call 6D77B790 

代码已经移动,但请注意,在地址5c它现在使用本地variables(值)而不是null。

你可以在connect.microsoft.com上报告这个错误。 解决方法很简单:

  if (value != null) { Console.WriteLine("Post-check Value is: " + value); new PrintManager().Print("blah", value); } 

这个错误似乎已经在.NET 4(testing版2)中得到了修复。 以下是针对上面突出显示的bit nobugz优化的x86反汇编:

  Console.WriteLine("Post-check Value is: " + value); 00000056 mov ecx,dword ptr ds:[033C2090h] 0000005c mov edx,dword ptr [ebp-8] 0000005f call 65D8FE10 

该程序还显示了优化和未优化模式下的预期输出。

 value == new string[0] 

上面看起来像一个奇怪的声明给我。 您正在比较两个string数组与一个equals语句。 这只会导致如果他们都指向相同的arrays,这是不太可能的。 这并没有解释为什么这个代码在优化版本中performance不同。

我在x64上,一开始就不能重现问题。 然后我把目标指定为x86,这发生在我身上。 回到x64,它就消失了。 不知道这是什么意思,但是我已经来回了几次了。

当然,看起来像一个错误,当你交换这样的操作符操作数时会重现吗?

 if (false == (null == value || new string[0] == value))