我遇到了代码中的错误,只有在启用了优化的情况下构建代码时才会重现。我制作了一个控制台应用程序来复制测试逻辑(下面的代码)。你会看到,当启用优化时,'value'在执行这个无效逻辑后变为null:
if ((value == null || value == new string[0]) == false)
修复是直截了当的,并在违规代码下方注释掉。但是......我更担心的是我可能遇到了汇编程序中的错误,或者其他人可能会解释为什么将值设置为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:
我的Env是运行带有.NET 3.5 SP1的Windows Server 2003 R2的VM。使用VS2008 Team System。
谢谢,
布赖恩
答案 0 :(得分:45)
是的,你的表达式致命地混淆了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,因此它直接将null传递给String.Concat()。
为了进行比较,这是关闭JIT优化时生成的代码:
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,它现在使用局部变量(值)而不是null。
您可以在connect.microsoft.com上报告此错误。解决方法很简单:
if (value != null)
{
Console.WriteLine("Post-check Value is: " + value);
new PrintManager().Print("blah", value);
}
答案 1 :(得分:3)
这个错误似乎已在.NET 4(beta 2)中得到修复。这是上面突出显示的位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
该程序还以优化和未优化模式显示预期输出。
答案 2 :(得分:2)
value == new string[0]
以上看起来像是一个奇怪的声明。您正在将两个字符串数组与equals语句进行比较。如果它们都指向同一个数组,那只会导致为真,这是不太可能的。这并没有解释为什么这个代码在优化版本中表现不同。
答案 3 :(得分:1)
我在x64上并且最初无法重现该问题。然后我将目标指定为x86,它发生在我身上。回到x64,它就消失了。不确定这究竟是什么意思,但我现在已经来过几次了。
答案 4 :(得分:0)
当然看起来像一个错误,当你交换像这样的操作员操作数时它会重现吗?
if (false == (null == value || new string[0] == value))