C# 我想我的团队在64位编译器中发现了一个bug,其他人能确认或者告诉我为什么这是正确的吗?
我有一个简单的关于这个可能的bug的洁净室示例C# 我想我的团队在64位编译器中发现了一个bug,其他人能确认或者告诉我为什么这是正确的吗?,c#,.net,debugging,C#,.net,Debugging,我有一个简单的关于这个可能的bug的洁净室示例 static void Main(string[] args) { bool MyFalse = false; if (MyFalse) { throw new Exception(); } try { int i = 0; } catch (Exceptio
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中preferred 32bit设置为false时),如果在If块中放置断点,则始终命中该断点
我们在VS2012、VS2010和VS2008中试过,它们在64位编译时都触发了if块,但在32位编译时却没有触发if块
我们查看了32位和64位版本的IL,它们看起来是一样的
我们在生产代码中发现了这一点,因为无论布尔变量的值是多少,都会运行if块并引发异常,尽管在这个简单的示例中,我们似乎无法引发异常,它是在生产代码中发生的。
因为它发生在生产代码中,所以它不仅仅是一个调试器问题
非常奇怪的行为,但似乎没有实际运行if块中的任何代码。开发者认为这是他所看到的一个例外,于是立即采取行动
(所有调试均处于调试模式-生产正在发布)
如果抛出被注释掉-未达到If块。在优化代码中,MSIL与本机机器代码和源代码之间没有严格的相关性。这会导致调试器有时高亮显示与正在执行的代码不同的代码,在单步执行时多次高亮显示同一行,或者将断点放置在与预期位置不同的位置
这是调试优化代码的一个基本问题,表示调试信息格式的不足。编译器或调试器中都没有bug。您可能需要在反汇编视图中进行调试。好的,我明白了。在64位调试器的调试构建中,这确实会出错。关键是准确地在if()语句上设置断点,然后开始单步执行。看起来好像正在执行throw语句。但如果实际情况并非如此,那么实际的代码执行是正确的 要查看发生了什么,请让它进入throw语句行。然后使用调试+反汇编查看它的实际位置。在我的机器上,它看起来像这样:
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;
if(MyFalse)
000000 40 movzx ecx,字节ptr[rbp+8]
00000044异或eax,eax
00000046测试ecx,ecx
00000048塞特艾尔
000000 4B mov dword ptr[rbp+1Ch],eax
0000004e movzx eax,字节ptr[rbp+1Ch]
000000 52 mov字节ptr[rbp+18h],al
00000055 movzx eax,字节ptr[rbp+18h]
00000059测试eax,eax
0000005b jne 00000000000000 88//听起来更像是调试器将断点放在错误的位置。是否引发异常?如果断点设置在没有代码的行上,IDE是否会将断点移动到下一个有代码的行。既然编译器可以删除if
,这就是发生的事情吗?我明白你在说什么了。您可以像执行一样进入throw new Exception()
行,但显然不是这样,因为没有引发异常,也不会触发断点。@NeilKnight:断点的存在是否会改变行为(即,异常仅在有断点时发生,或者总是发生?)如果程序是在调试模式下构建的,那么这听起来像一个bug;您可以在connect.microsoft.com上报告。如果它是在发布模式下构建的,那么这是意料之中的;调试器在调试未在调试模式下编译的代码方面做得很差。(正如Raymond所说,我简直不敢相信我必须这么说。:-)@Magnus:在.NET中进行拆分编译的副作用:优化分为两个阶段:在转换为MSIL的过程中,以及在JIT转换为本机机器代码的过程中。您确定它们都被禁用了吗?只有生成属性中的一个。(不知道其他的)@Magnus:你可以使用Reflector(或dotPeek等)检查C#编译器是否添加了DebuggableAttribute
并设置禁用优化
。在附加调试器时,Visual Studio的配置还可以禁止(或不禁止)优化。那么为什么它只对64位而不是32位执行优化?这个答案的最大问题是,它没有解释为什么在未优化的代码中会出现错误。这不是正确的答案。“轻微的困惑”我曾经有过类似的事情,那就是调试器在向我撒谎;有几个小时,我感到非常困惑