【问题标题】:Bug only occurring when compile optimization enabled错误仅在启用编译优化时发生
【发布时间】:2011-01-09 06:45:04
【问题描述】:

我在代码中遇到了一个错误,只有在启用优化的情况下构建代码时才会重现该错误。我制作了一个控制台应用程序,它复制了测试逻辑(下面的代码)。您会看到,启用优化后,执行此无效逻辑后,“值”变为空:

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:   

My Env 是一个运行 Windows Server 2003 R2 和 .NET 3.5 SP1 的 VM。使用VS2008团队系统。

谢谢,

布赖恩

【问题讨论】:

  • 显然,优化器对你使用 '== false' 而不是应用 !表达式的运算符。
  • 当你需要 Eric Lippert 时他在哪里 ;-p
  • 我会把这个转发给 jitter 团队。谢谢!
  • 看,人们 - @Eric Beetlejuice,说出他的时间 3 次,他就会出现。
  • 这已被分配 CVE-2011-1271 - Microsoft .NET Framework 4 beta 2 之前的 JIT 编译器,当 IsJITOptimizerDisabled 为 false 时,不能正确处理与空字符串相关的表达式,这允许上下文-依赖攻击者通过利用精心设计的应用程序绕过机会主义情况下的预期访问限制,如 x86 平台上的 C# 应用程序所示。

标签: c# compiler-optimization


【解决方案1】:

是的,您的表达式严重混淆了 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,优化器得出的结论是 value 将始终为 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);
  }

【讨论】:

  • 感谢您对正在发生的事情的精彩解释。
  • 这很容易是我在 SO 上见过的最令人印象深刻的答案......或者我只是很容易印象深刻......
  • 不应该是“if (!string.IsNullOrEmpty(value))”,因为 OP 也在与空字符串进行比较。
【解决方案2】:

此错误似乎已在 .NET 4(beta 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

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

【讨论】:

    【解决方案3】:
    value == new string[0]
    

    对我来说,上面的陈述看起来很奇怪。您正在使用 equals 语句比较两个字符串数组。如果它们都指向同一个数组,那只会导致 true,这是不太可能的。这还不能解释为什么这段代码在优化版本中表现不同。

    【讨论】:

    • 想不出任何方法来为此注入运算符重载,但这绝对是 100% 真实的我的奇迹吗?与此同时,这就是我的想法,所以 +1
    【解决方案4】:

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

    【讨论】:

    • 我也在 x64 上,无法通过优化 =true 和 target=x86 重现这一点。
    【解决方案5】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      • 1970-01-01
      • 2021-11-14
      • 1970-01-01
      • 2018-04-06
      • 1970-01-01
      相关资源
      最近更新 更多