仅当启用编译优化时才会出现错误
我在代码中遇到了一个错误,该错误仅在启用优化的情况下构建代码时才会重现。我制作了一个控制台应用程序来复制测试逻辑(代码如下)。您将看到,启用优化后,执行此无效逻辑后,“值”将变为空:
if ((value == null || value == new string[0]) == false)
修复方法很简单,并在有问题的代码下方注释掉。但是......我更担心我可能遇到了汇编程序中的错误,或者其他人可能对为什么值设置为空有解释。
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:
My Env is a VM running Windows Server 2003 R2 with .NET 3.5 SP1。使用VS2008团队系统。
谢谢,
布莱恩
I came across a bug in code that is only reproduced when the code is built with optimizations enabled. I've made a console app that replicates the logic for testing (code below). You'll see that when optimization is enabled 'value' becomes null after execution of this invalid logic:
if ((value == null || value == new string[0]) == false)
The fix is straight forward and is commented out below the offending code. But... I'm more concerned that I may have come across a bug in the assembler or perhaps someone else has an explanation of why value gets set to 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);
//}
}
}
}
}
The normal output should be:
Pre-check Value is: System.String[]
Post-check Value is: System.String[]
Key is: blah
Value is: System.String[]
The buggy output is:
Pre-check Value is: System.String[]
Post-check Value is:
Key is: blah
Value is:
My Env is a VM running Windows Server 2003 R2 with .NET 3.5 SP1. Using VS2008 Team System.
Thanks,
Brian
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的,你的表达式严重迷惑了 JIT 优化器。生成的机器代码如下所示:
bug 发生在地址 41 处,优化器得出结论 value 将始终为 null,因此它直接将 null 传递给 String.Concat()。
为了进行比较,这是关闭 JIT 优化时生成的代码:
代码已移动,但请注意,在地址 5c 处,它现在使用局部变量(值)而不是 null。
您可以在 connect.microsoft.com 上报告此错误。解决方法很简单:
Yes, your expression fatally confuses the JIT optimizer. The generated machine code looks like this:
The bug occurs at address 41, the optimizer has concluded that value will always be null so it directly passes a null to String.Concat().
For comparison, this is the code that's generated when JIT optimization is turned off:
The code got moved, but do note that at address 5c it now uses the local variable (value) instead of null.
You can report this bug at connect.microsoft.com. The workaround is simple:
此错误似乎已在 .NET 4(beta 2)中修复。下面是上面突出显示的 nobugz 位的优化 x86 反汇编:
该程序还显示优化和未优化模式下的预期输出。
This bug seems to have been fixed in .NET 4 (beta 2). Here's the optimized x86 disassembly for the bit nobugz highlighted, above:
The program also displays the expected output in both optimized and unoptimized modes.
上面的说法对我来说看起来很奇怪。您正在使用 equals 语句比较两个字符串数组。只有当它们都指向同一个数组时,结果才会为 true,但这是不太可能的。这还不能解释为什么这段代码在优化版本中表现不同。
The above looks like a weird statement to me. You are comparing two string arrays with an equals statement. That will only result in true if they both point to the same array, which is quite unlikely. This doesn't explain yet why this code behaves differently in an optimized version.
我使用的是 x64,一开始无法重现该问题。然后我将目标指定为x86,这发生在我身上。回到x64,它就消失了。不确定这到底意味着什么,但我已经来回了好几次了。
I'm on x64 and couldn't reproduce the problem at first. Then I specified the target as x86, and it happened to me. Back to x64, and it went away. Not sure what this means, exactly, but I've gone back and forth a few times now.
当然看起来像一个错误,当你像这样交换运算符操作数时它会重现吗?
Certainly looks like a bug, does it reproduce when you swap the operator operands like this?