我有一个简单的洁净室可能的错误示例。
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块。
答案 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与本机机器代码和源代码之间没有严格的关联。这会导致调试器有时突出显示与正在执行的代码不同的代码,在单步执行时多次突出显示相同的行,或者将断点放在与您预期的位置不同的位置。
这是调试优化代码的基本问题,并且代表调试信息格式的不足之处。编译器或调试器中没有错误。您可能不得不在反汇编视图中使用调试。