我想我的团队在64位编译器中发现了一个错误,其他人可以确认或告诉我为什么这是正确的吗?

时间:2013-05-03 18:54:07

标签: c# .net debugging

我有一个简单的洁净室可能的错误示例。

   static void Main(string[] args)
    {
        bool MyFalse = false;

        if (MyFalse)
        {
            throw new Exception();
        }
        try
        {
            int i = 0;
        }
        catch (Exception e)
        {
            Console.Write(e);
        }

        Console.Read();
    }

如果在x64或AnyCPU中编译(当在VS2012中将32位设置为false时),如果在if块中放置断点,则它总是被命中。

我们在VS2012,VS2010和VS2008中尝试了它们,当它们在64位编译时它们都触发了if块,但在32位中它不会触发if块。

我们查看了IL的32位和64位版本,它们看起来一样。

我们在生产代码中发现了这个,因为if块正在运行并且抛出异常而不管boolean变量的值是多少,尽管在简单示例中我们似乎无法抛出异常,它是发生在生产代码中。

由于它在生产代码中发生,因此它不仅仅是调试器问题。

非常奇怪的行为,但似乎没有在if块中实际运行任何代码。假设这是他所看到的例外情况,开发商跳了起来。

(所有调试都处于调试模式 - 生产正在发布中)

如果抛出注释 - 未达到if块。

2 个答案:

答案 0 :(得分:20)

好的,我明白了。这在64位调试器的Debug构建中确实出错了。关键是在if()语句中准确设置断点,然后开始步进。它将看起来,就像throw语句被执行一样。但它实际上并没有发生,实际的代码执行是正确的。

要查看正在发生的事情,请将其放入throw语句行。然后使用Debug + Disassembly查看它实际所在的位置。在我的机器上它看起来像这样:

       if (MyFalse)
00000040  movzx       ecx,byte ptr [rbp+8] 
00000044  xor         eax,eax 
00000046  test        ecx,ecx 
00000048  sete        al 
0000004b  mov         dword ptr [rbp+1Ch],eax 
0000004e  movzx       eax,byte ptr [rbp+1Ch] 
00000052  mov         byte ptr [rbp+18h],al 
00000055  movzx       eax,byte ptr [rbp+18h] 
00000059  test        eax,eax 
0000005b  jne         0000000000000088            // <=== Note this jump
        {
0000005d  nop 
            throw new Exception();
0000005e  lea         rcx,[5B848928h] 
00000065  call        000000005F65E9E0 
0000006a  mov         qword ptr [rbp+20h],rax 
0000006e  mov         rax,qword ptr [rbp+20h] 
00000072  mov         qword ptr [rbp+28h],rax 
00000076  mov         rcx,qword ptr [rbp+28h] 
0000007a  call        000000005BE4A5D0 
0000007f  mov         rcx,qword ptr [rbp+28h] 
00000083  call        000000005F73E36C 
00000088  nop                                     // <=== yellow arrow here
        }
        try
        {
00000089  nop 
            int i = 0;

您甚至可以从调试器使用C#语句对机器代码指令进行分组的方式来查看它。注意调试器如何对地址0088处的NOP感到困惑。它认为它属于复合if()语句。因此它将黄色突出显示在块内。但该程序实际上已经在地址005b处跳转并跳过了throw语句(地址005e到0083)。

不太确定在哪一个指责,不能责怪C#编译器或PDB文件,因为它在32位模式下正常运行。它闻起来像一个抖动问题,值得注意的是x86抖动不会产生NOP指令。您还可以假设抖动应该生成JNE指令以跳转到地址0089.这些只是猜测,您可以在connect.microsoft.com获得真正的答案

请记住这个怪癖,直到您收到回复或我们都在服务包中获得更新为止。代码实际上是正确执行的,所以你只会遇到一些困惑的情况。

答案 1 :(得分:10)

在优化代码中,MSIL与本机机器代码和源代码之间没有严格的关联。这会导致调试器有时突出显示与正在执行的代码不同的代码,在单步执行时多次突出显示相同的行,或者将断点放在与您预期的位置不同的位置。

这是调试优化代码的基本问题,并且代表调试信息格式的不足之处。编译器或调试器中没有错误。您可能不得不在反汇编视图中使用调试。