C# 只有在启用编译优化时才会出现错误
我在代码中遇到了一个bug,只有在代码构建时启用了优化,它才会被复制。我制作了一个控制台应用程序,可以复制测试逻辑(下面的代码)。您将看到,当启用优化时,在执行此无效逻辑后,“value”变为null:C# 只有在启用编译优化时才会出现错误,c#,compiler-optimization,C#,Compiler Optimization,我在代码中遇到了一个bug,只有在代码构建时启用了优化,它才会被复制。我制作了一个控制台应用程序,可以复制测试逻辑(下面的代码)。您将看到,当启用优化时,在执行此无效逻辑后,“value”变为null: if ((value == null || value == new string[0]) == false) 修正是直截了当的,并在有问题的代码下面注释掉。但是我更担心的是,我可能在汇编程序中遇到了一个bug,或者其他人解释了为什么将value设置为null using System; us
if ((value == null || value == new string[0]) == false)
修正是直截了当的,并在有问题的代码下面注释掉。但是我更担心的是,我可能在汇编程序中遇到了一个bug,或者其他人解释了为什么将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[]
buggy的输出是:
Pre-check Value is: System.String[]
Post-check Value is:
Key is: blah
Value is:
My Env是一个运行Windows Server 2003 R2和.NET 3.5 SP1的虚拟机。使用VS2008团队系统 谢谢
Brian我使用的是x64,一开始无法重现该问题。然后我将目标指定为x86,我就遇到了这种情况。回到x64,它就消失了。我不确定这到底意味着什么,但我已经来回走了好几次了
value == new string[0]
在我看来,上面的说法很奇怪。您正在使用equals语句比较两个字符串数组。只有当它们都指向同一个数组时,才会出现true,这是不太可能的。这还不能解释为什么这段代码在优化版本中表现不同。是的,您的表达式会严重混淆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);
}
当然看起来像个bug,当你像这样交换操作符操作数时它会重现吗
if (false == (null == value || new string[0] == value))
这个错误似乎已经在.NET4(Beta2)中修复。下面是上面突出显示的位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
程序还以优化和未优化模式显示预期输出。显然,优化器对您使用“==false”而不是应用!表达式的运算符。需要时Eric Lippert在哪里-pI会将此转发给jitter团队。谢谢请看,people-@Eric是甲壳虫汁,说了3次他的时间,他出现了。这已经被分配给CVE-2011-1271-4 beta 2之前的Microsoft.NET Framework中的JIT编译器,当IsJITOptimizerDisabled为false时,无法正确处理与空字符串相关的表达式,允许上下文相关攻击者利用特制的应用程序,在机会主义情况下绕过预期的访问限制,正如x86平台上的一个C#应用程序所演示的那样。我也在x64上,无法用optimization=true和target=x86重现这一点。感谢您对所发生的事情进行了精彩的解释。这是我在x64上看到的最令人印象深刻的答案,所以。。。或者我只是很容易被打动…不应该是“if(!string.IsNullOrEmpty(value)),因为OP也比较空字符串。我想不出任何方法来注入运算符重载,但这绝对是100%真实的吗?同时,我也这么想,所以+1