仅当启用编译优化时才会出现错误

发布于 2024-08-19 07:20:23 字数 2066 浏览 2 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

有木有妳兜一样 2024-08-26 07:20:23

是的,你的表达式严重迷惑了 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()

bug 发生在地址 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);
  }

Yes, your expression fatally confuses the JIT optimizer. The generated machine code looks like this:

                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()

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:

                    Console.WriteLine("Post-check Value is: " + value);
00000056  mov         ecx,dword ptr ds:[03342090h] 
0000005c  mov         edx,dword ptr [ebp-8] 
0000005f  call        6D77B790 

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:

  if (value != null)
  {
    Console.WriteLine("Post-check Value is: " + value);
    new PrintManager().Print("blah", value);
  }
壹場煙雨 2024-08-26 07:20:23

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

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

This bug seems to have been fixed in .NET 4 (beta 2). Here's the optimized x86 disassembly for the bit nobugz highlighted, above:

                    Console.WriteLine("Post-check Value is: " + value);
00000056  mov         ecx,dword ptr ds:[033C2090h] 
0000005c  mov         edx,dword ptr [ebp-8] 
0000005f  call        65D8FE10

The program also displays the expected output in both optimized and unoptimized modes.

慢慢从新开始 2024-08-26 07:20:23
value == new string[0]

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

value == new string[0]

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.

浪荡不羁 2024-08-26 07:20:23

我使用的是 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.

与君绝 2024-08-26 07:20:23

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

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

Certainly looks like a bug, does it reproduce when you swap the operator operands like this?

if (false == (null == value || new string[0] == value))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文