仅在启用编译优化时发生错误

bma*_*ini 44 c# compiler-optimization

我遇到了代码中的错误,只有在启用了优化的情况下构建代码时才会重现.我制作了一个控制台应用程序来复制测试逻辑(下面的代码).你会看到,当启用优化时,'value'在执行这个无效逻辑后变为null:

if ((value == null || value == new string[0]) == false)
Run Code Online (Sandbox Code Playgroud)

修复是直截了当的,并在违规代码下方注释掉.但是......我更担心的是我可能遇到了汇编程序中的错误,或者其他人可能会解释为什么将值设置为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);
                //}
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正常输出应该是:

Pre-check Value is: System.String[]
Post-check Value is: System.String[]
Key is: blah
Value is: System.String[]
Run Code Online (Sandbox Code Playgroud)

越野车的输出是:

Pre-check Value is: System.String[]
Post-check Value is:
Key is: blah
Value is:   
Run Code Online (Sandbox Code Playgroud)

我的Env是运行带有.NET 3.5 SP1的Windows Server 2003 R2的VM.使用VS2008 Team System.

谢谢,

布赖恩

Han*_*ant 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()
Run Code Online (Sandbox Code Playgroud)

错误发生在地址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 
Run Code Online (Sandbox Code Playgroud)

代码被移动了,但请注意,在地址5c,它现在使用局部变量(值)而不是null.

您可以在connect.microsoft.com上报告此错误.解决方法很简单:

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

  • 这很容易就是我见过的最令人印象深刻的答案......也许我只是很容易让人印象深刻...... (6认同)
  • 感谢您对正在发生的事情的精彩解释. (2认同)