我遇到了一些非常奇怪的问题。
我正在开发一些连接到webservices的类库。该库由桌面应用程序使用。
在我现在的代码中:
Int32 errorCode32 = errorCode;
Int32 errorTimeout = 300;
if (errorCode32.Equals(errorTimeout) == false)
{
System.Console.Out.WriteLine("aaa");
return;
}
其中errorCode等于300.所以乍一看它是可见的,如果不应该执行errorCode == 300而不是if语句中的代码,因为它被定义为仅当errorCode不等于300时执行
直到现在一切都很清楚,但现在整个乐趣开始了。
应用程序正在运行,并执行带有上述代码段的方法。 errorCode等于300,预期的结果是应用程序不会在if语句中执行任何代码,因为整个语句是false。但实际上应用程序进入“if”并立即跳转到“return”语句。 System.Console.Out ...永远不会执行。如果我用“throw new SomeException()”
替换干净的“return”语句Int32 errorCode32 = errorCode;
Int32 errorTimeout = 300;
if (errorCode32.Equals(errorTimeout) == false)
{
System.Console.Out.WriteLine("aaa");
throw new SomeException();
}
我会得到相同的结果。应用程序进入if语句(注意:[errorCode32.Equals(errorTimeout)== false]在我的情况下为false),不执行Console.Out ...但抛出SomeException。
我多次重建了所有内容,删除了所有二进制文件,我甚至从磁盘中删除了整个项目,并从存储库再次检索到了清理文件夹。
我很困惑,我甚至反汇编代码,看看会发生什么(即使我不是汇编程序的专家)。但结果对我来说很奇怪。
反汇编代码如下:
50: Int32 errorCode32 = errorCode;
000000e5 mov eax,dword ptr [ebp-50h]
000000e8 mov dword ptr [ebp-54h],eax
51: Int32 errorTimeout = 300;
000000eb mov dword ptr [ebp-58h],12Ch
52:
53: if (errorCode32.Equals(errorTimeout) == false)
000000f2 lea ecx,[ebp-54h]
000000f5 mov edx,dword ptr [ebp-58h]
000000f8 call 699EB198
000000fd mov dword ptr [ebp-68h],eax
00000100 movzx eax,byte ptr [ebp-68h]
00000104 mov dword ptr [ebp-48h],eax
00000107 cmp dword ptr [ebp-48h],0
0000010b jne 00000134
54: {
0000010d nop
55: System.Console.Out.WriteLine("aaa");
0000010e call 69538768
00000113 mov dword ptr [ebp+FFFFFF7Ch],eax
00000119 mov edx,dword ptr ds:[0302CE30h]
0000011f mov ecx,dword ptr [ebp+FFFFFF7Ch]
00000125 mov eax,dword ptr [ecx]
00000127 call dword ptr [eax+000000D8h]
0000012d nop
56: return;
0000012e nop
0000012f jmp 00000287
00000134 mov eax,dword ptr ds:[0302CE34h]
0000013a mov dword ptr [ebp-6Ch],eax
0000013d mov edx,5
00000142 mov ecx,6EDE3FBEh
00000147 call FA68D488
0000014c mov dword ptr [ebp-70h],eax
57: }
当我调试指令时,我可以理解在行之前会发生什么:
00000104 mov dword ptr [ebp-48h],eax
我希望存储在eax中的值将被复制到位置“dword ptr [ebp-48h]”,并且应用程序将转到下一行(00000107)。但这不会发生。当我试图跨越00000104行时,应用程序立即跳转到行
00000134 mov eax,dword ptr ds:[0302CE34h]
我无法理解这里发生了什么。我试图通过互联网搜索,但我找不到任何有用的东西。有没有人有什么建议可能是问题的原因或解决方法?
修改
我忘记了使用Visual Studio 2008并编译成.NET 3.5的信息。 已安装所有更新。
修改
C#中的整个方法
private void nativeDocumentServiceWrapper_PostInvokeEvents(object sender, WebServiceInvokeEventArgs e)
{
Exception exception = e.Exception;
if (exception == null)
{
_invokeRetries = 0;
return;
}
string errorCodeString = ErrorHandler.GetErrorCodeString(exception);
int errorCode;
if (int.TryParse(errorCodeString, out errorCode))
{
e.Exception = new VaultException(errorCode, exception);
}
Int32 errorCode32 = errorCode;
Int32 errorTimeout = 300;
if (errorCode32.Equals(errorTimeout) == false)
{
System.Console.Out.WriteLine("aaa");
return;
}
Trace.TraceWarning("Invoke failed (count: {4}) {0}.{1} #{2} error '{3}'", _moduleName, e.MethodName, _id, errorCodeString, _invokeRetries + 1);
if (_invokeRetries > 0)
{
//int errorCode;
if (int.TryParse(errorCodeString, out errorCode))
{
//throw new VaultException(errorCode, exception);
e.Exception = new VaultException(errorCode, exception);
}
return;
}
e.Exception = null;
// we ran into error 300 or 319
// the solution is to log in again and re-run the command
tryReloginAndInvokeVaultMethodAgain(e);
}
并反汇编:
34: private void nativeDocumentServiceWrapper_PostInvokeEvents(object sender, WebServiceInvokeEventArgs e)
35: {
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,84h
0000000c mov esi,ecx
0000000e lea edi,[ebp-54h]
00000011 mov ecx,12h
00000016 xor eax,eax
00000018 rep stos dword ptr es:[edi]
0000001a mov ecx,esi
0000001c xor eax,eax
0000001e mov dword ptr [ebp-1Ch],eax
00000021 mov dword ptr [ebp-3Ch],ecx
00000024 mov dword ptr [ebp-40h],edx
00000027 cmp dword ptr ds:[01AD2DD8h],0
0000002e je 00000035
00000030 call 6AB8A719
00000035 mov dword ptr [ebp-48h],0
0000003c xor edx,edx
0000003e mov dword ptr [ebp-5Ch],edx
00000041 xor edx,edx
00000043 mov dword ptr [ebp-44h],edx
00000046 xor edx,edx
00000048 mov dword ptr [ebp-4Ch],edx
0000004b xor edx,edx
0000004d mov dword ptr [ebp-58h],edx
00000050 nop
36: Exception exception = e.Exception;
00000051 mov eax,dword ptr [ebp+8]
00000054 mov eax,dword ptr [eax+4]
00000057 mov dword ptr [ebp-44h],eax
37: if (exception == null)
0000005a cmp dword ptr [ebp-44h],0
0000005e setne al
00000061 movzx eax,al
00000064 mov dword ptr [ebp-48h],eax
00000067 cmp dword ptr [ebp-48h],0
0000006b jne 0000007F
38: {
0000006d nop
39: _invokeRetries = 0;
0000006e mov eax,dword ptr [ebp-3Ch]
00000071 xor edx,edx
00000073 mov dword ptr [eax+00000088h],edx
40: return;
00000079 nop
0000007a jmp 00000287
41: }
42:
43: string errorCodeString = ErrorHandler.GetErrorCodeString(exception);
0000007f mov ecx,dword ptr [ebp-44h]
00000082 call FF0827F0
00000087 mov dword ptr [ebp-60h],eax
0000008a mov eax,dword ptr [ebp-60h]
0000008d mov dword ptr [ebp-4Ch],eax
44: int errorCode;
45: if (int.TryParse(errorCodeString, out errorCode))
00000090 lea edx,[ebp-50h]
00000093 mov ecx,dword ptr [ebp-4Ch]
00000096 call 694B44A8
0000009b mov dword ptr [ebp-64h],eax
0000009e cmp dword ptr [ebp-64h],0
000000a2 sete al
000000a5 movzx eax,al
000000a8 mov dword ptr [ebp-48h],eax
000000ab cmp dword ptr [ebp-48h],0
000000af jne 000000E5
46: {
000000b1 nop
47: e.Exception = new VaultException(errorCode, exception);
000000b2 mov ecx,5482E0Ch
000000b7 call FA68D364
000000bc mov dword ptr [ebp+FFFFFF78h],eax
000000c2 push dword ptr [ebp-44h]
000000c5 mov edx,dword ptr [ebp-50h]
000000c8 mov ecx,dword ptr [ebp+FFFFFF78h]
000000ce call FF07FCB0
000000d3 mov edx,dword ptr [ebp+8]
000000d6 mov eax,dword ptr [ebp+FFFFFF78h]
000000dc lea edx,[edx+4]
000000df call 6A90E288
48: }
000000e4 nop
49:
50: Int32 errorCode32 = errorCode;
000000e5 mov eax,dword ptr [ebp-50h]
000000e8 mov dword ptr [ebp-54h],eax
51: Int32 errorTimeout = 300;
000000eb mov dword ptr [ebp-58h],12Ch
52:
53: if (errorCode32.Equals(errorTimeout) == false)
000000f2 lea ecx,[ebp-54h]
000000f5 mov edx,dword ptr [ebp-58h]
000000f8 call 699EB198
000000fd mov dword ptr [ebp-68h],eax
00000100 movzx eax,byte ptr [ebp-68h]
00000104 mov dword ptr [ebp-48h],eax
00000107 cmp dword ptr [ebp-48h],0
0000010b jne 00000134
54: {
0000010d nop
55: System.Console.Out.WriteLine("aaa");
0000010e call 69538768
00000113 mov dword ptr [ebp+FFFFFF7Ch],eax
00000119 mov edx,dword ptr ds:[0302CE30h]
0000011f mov ecx,dword ptr [ebp+FFFFFF7Ch]
00000125 mov eax,dword ptr [ecx]
00000127 call dword ptr [eax+000000D8h]
0000012d nop
56: return;
0000012e nop
0000012f jmp 00000287
00000134 mov eax,dword ptr ds:[0302CE34h]
0000013a mov dword ptr [ebp-6Ch],eax
0000013d mov edx,5
00000142 mov ecx,6EDE3FBEh
00000147 call FA68D488
0000014c mov dword ptr [ebp-70h],eax
57: }
58:
59: Trace.TraceWarning("Invoke failed (count: {4}) {0}.{1} #{2} error '{3}'", _moduleName, e.MethodName, _id, errorCodeString, _invokeRetries + 1);
0000014f mov eax,dword ptr [ebp-70h]
00000152 mov dword ptr [ebp-5Ch],eax
00000155 mov eax,dword ptr [ebp-3Ch]
00000158 push dword ptr [eax+00000080h]
0000015e mov ecx,dword ptr [ebp-5Ch]
00000161 xor edx,edx
00000163 call 6A914654
00000168 mov eax,dword ptr [ebp+8]
0000016b push dword ptr [eax+8]
0000016e mov ecx,dword ptr [ebp-5Ch]
00000171 mov edx,1
00000176 call 6A914654
0000017b mov ecx,6F052DA0h
00000180 call FA68D364
00000185 mov dword ptr [ebp-74h],eax
00000188 mov eax,dword ptr [ebp-5Ch]
0000018b mov dword ptr [ebp+FFFFFF74h],eax
00000191 mov eax,dword ptr [ebp-3Ch]
00000194 mov eax,dword ptr [eax+00000084h]
0000019a mov edx,dword ptr [ebp-74h]
0000019d mov dword ptr [edx+4],eax
000001a0 mov eax,dword ptr [ebp-74h]
000001a3 push eax
000001a4 mov ecx,dword ptr [ebp+FFFFFF74h]
000001aa mov edx,2
000001af call 6A914654
000001b4 push dword ptr [ebp-4Ch]
000001b7 mov ecx,dword ptr [ebp-5Ch]
000001ba mov edx,3
000001bf call 6A914654
000001c4 mov ecx,6F052DA0h
000001c9 call FA68D364
000001ce mov dword ptr [ebp-78h],eax
000001d1 mov eax,dword ptr [ebp-5Ch]
000001d4 mov dword ptr [ebp+FFFFFF70h],eax
000001da mov eax,dword ptr [ebp-3Ch]
000001dd mov eax,dword ptr [eax+00000088h]
000001e3 inc eax
000001e4 mov edx,dword ptr [ebp-78h]
000001e7 mov dword ptr [edx+4],eax
000001ea mov eax,dword ptr [ebp-78h]
000001ed push eax
000001ee mov ecx,dword ptr [ebp+FFFFFF70h]
000001f4 mov edx,4
000001f9 call 6A914654
000001fe mov edx,dword ptr [ebp-5Ch]
00000201 mov ecx,dword ptr [ebp-6Ch]
00000204 call 69039D88
00000209 nop
60:
61: if (_invokeRetries > 0)
0000020a mov eax,dword ptr [ebp-3Ch]
0000020d cmp dword ptr [eax+00000088h],0
00000214 setle al
00000217 movzx eax,al
0000021a mov dword ptr [ebp-48h],eax
0000021d cmp dword ptr [ebp-48h],0
00000221 jne 00000273
62: {
00000223 nop
63: //int errorCode;
64: if (int.TryParse(errorCodeString, out errorCode))
00000224 lea edx,[ebp-50h]
00000227 mov ecx,dword ptr [ebp-4Ch]
0000022a call 694B44A8
0000022f mov dword ptr [ebp-7Ch],eax
00000232 cmp dword ptr [ebp-7Ch],0
00000236 sete al
00000239 movzx eax,al
0000023c mov dword ptr [ebp-48h],eax
0000023f cmp dword ptr [ebp-48h],0
00000243 jne 00000270
65: {
00000245 nop
66: //throw new VaultException(errorCode, exception);
67: e.Exception = new VaultException(errorCode, exception);
00000246 mov ecx,5482E0Ch
0000024b call FA68D364
00000250 mov dword ptr [ebp-80h],eax
00000253 push dword ptr [ebp-44h]
00000256 mov edx,dword ptr [ebp-50h]
00000259 mov ecx,dword ptr [ebp-80h]
0000025c call FF07FCB0
00000261 mov edx,dword ptr [ebp+8]
00000264 mov eax,dword ptr [ebp-80h]
00000267 lea edx,[edx+4]
0000026a call 6A90E288
68: }
0000026f nop
69: return;
00000270 nop
00000271 jmp 00000287
70: }
71:
72: e.Exception = null;
00000273 mov eax,dword ptr [ebp+8]
00000276 xor edx,edx
00000278 mov dword ptr [eax+4],edx
73:
74: // we ran into error 300 or 319
75: // the solution is to log in again and re-run the command
76:
77: tryReloginAndInvokeVaultMethodAgain(e);
0000027b mov edx,dword ptr [ebp+8]
0000027e mov ecx,dword ptr [ebp-3Ch]
00000281 call FF0876C0
00000286 nop
78: }
答案 0 :(得分:2)
您已启用优化,编译器将if
语句中的return语句与函数末尾的return语句组合在一起。两者具有相同的地址,调试器无法分辨要突出显示哪一行源代码,因为两者都匹配。
没有任何错误。但是,如果您希望逐步调试调试器以正常工作,则必须禁用优化。
这只是优化器可以用来混淆调试器的几个方面之一。其他可能性是重新排序没有数据依赖性的语句(以优化管道),甚至将语句分开并在其间放置另一个语句。
答案 1 :(得分:0)
我花了更多的时间来调查这个问题,我有一些我想分享的结论,即使这意味着我必须承认我做了几个错误的假设而且我无法全面了解整个行为
首先:我提供的代码旨在处理使用某些第三方库时的某些特定问题。这些库的未记录的行为是在某些情况下它会在某些条件下抛出异常。原来的问题来自这样一个事实,即使我们“处理”错误情况,该库也会抛出异常
第二:调试时发现以下情况:
1 if (someVariable)
2 {
3 someCode();
4 someOtherCode();
5 throw someExceptionPassedFromTheThirdPartyLibrary;
6 }
7 somethingElse();
调试器在第1行停止,someVariable为false,跳过,调试器在第5行等待。在这里我做了第一个错误的假设 - 就是我的异常从这里抛出。
第三:我开始尝试了。 “someVariable”总是假的,但有时调试器从第1行跳到第7行,有时从1跳到5.我决定使用反汇编程序。 第四:我无法理解反汇编代码的行为,它使我的思想固定在想法上,即if语句行为不正确。另外我发现文章“http://stackoverflow.com/questions/6054987/if-statement-appears-to-be-evaluating-even-when-condition-evaluates-to-false”[已确认的JIT bug]这次帮助了我。好的我认为在经过一些额外的背景后,现在是时候解释我的代码中发生了什么。
一般情况下,在我的情况下,“if”语句表现正确。我理解当我学习更多有关汇编器和现代处理器架构的内容时。
53: if (errorCode32.Equals(errorTimeout) == false)
000000f2 lea ecx,[ebp-54h]
000000f5 mov edx,dword ptr [ebp-58h]
000000f8 call 699EB198
000000fd mov dword ptr [ebp-68h],eax
00000100 movzx eax,byte ptr [ebp-68h]
00000104 mov dword ptr [ebp-48h],eax
00000107 cmp dword ptr [ebp-48h],0
0000010b jne 00000134
54: {
0000010d nop
55: System.Console.Out.WriteLine("aaa");
0000010e call 69538768
00000113 mov dword ptr [ebp+FFFFFF7Ch],eax
00000119 mov edx,dword ptr ds:[0302CE30h]
0000011f mov ecx,dword ptr [ebp+FFFFFF7Ch]
00000125 mov eax,dword ptr [ecx]
00000127 call dword ptr [eax+000000D8h]
0000012d nop
56: return;
0000012e nop
0000012f jmp 00000287
00000134 mov eax,dword ptr ds:[0302CE34h]
0000013a mov dword ptr [ebp-6Ch],eax
0000013d mov edx,5
00000142 mov ecx,6EDE3FBEh
00000147 call FA68D488
0000014c mov dword ptr [ebp-70h],eax
57: }
偏移量00000104-0000010b处的指令执行由处理器架构优化(可能发生跳转预测,或其他一些核心处理器优化)。因此,处理器不是一次调用三条指令,而是一步完成所有操作。因为在00000107中应该比较的值不相等,所以处理器跳转到00000134.此时我无法理解这里实际发生了什么,所以我假设它只是执行“返回”指令。事实很简单 - “if from if”指令不是00000134,但是指令更加简单 - 在0000012f,这只是简单的无条件跳转。
当我理解这一点时,我知道这段代码的行为是正确的。所以我再次搬到C#,我找到了让我感到羞耻的东西。因为当我再次调试代码时,我发现它的行为方式如下:
1 if (someVariable)
2 {
3 someCode();
4 someOtherCode();
5 throw someExceptionPassedFromTheThirdPartyLibrary;
6 }
7 somethingElse();
断点1,F10 当前线路指示器为5,按F10 当前行指示器为7,按F10 ......依此类推。
所以我理解调试器在最后的“if”指令内部执行,但不执行该指令。这是一个错误 - 但不是“if”处理,只在VS调试器中。此外,该错误并不重要,因为它实际上只是表示,并且对调试的代码没有任何影响。