2012-01-13 10 views
5

私は本当に奇妙な問題に遭遇しました。ifステートメントが正しく動作しない - 逆アセンブルが何も説明しない

私はwebservicesに接続するいくつかのクラスライブラリに取り組んでいます。ライブラリはデスクトップアプリケーションで使用されます。私は今持っているコードで

:ErrorCodeが300に等しい

Int32 errorCode32 = errorCode; 
Int32 errorTimeout = 300; 

if (errorCode32.Equals(errorTimeout) == false) 
{ 
    System.Console.Out.WriteLine("aaa"); 
    return; 
} 

だから一見それはifステートメント内のコードより場合のerrorCodeの== 300が実行されるべきでないことは、表示されていますerrorCodeが300に等しくない場合にのみ実行されるように定義されているためです。

これまでのところ、すべてがはっきりしていましたが、今は楽しいものです。

アプリケーションが動作しており、上記コードスニペットのメソッドが実行されます。 errorCodeが300に等しいことは、文全体が偽であるため、アプリケーションがifステートメント内のコードを実行しないことが期待される結果です。しかし、実際にはアプリケーションは "if"の内部に入り、すぐに "return"ステートメントにスキップします。 System.Console.Out ...は決して実行されません。私がきれいな "return"ステートメントを "新しいSomeException()をスローする"に置き換えた場合

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にコンパイルしていた情報を入れるのを忘れていました。 すべての更新プログラムがインストールされています。


編集

 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); 
     } 

とを分解C#で

全体方法:

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

アダム - これが最初にチェックしたものです。私は何度もすべてを再構築し、すべてのバイナリを削除し、ディスクから全体のプロジェクトを削除して、リポジトリからクリーンフォルダに再度取り出したことにも注意してください。 –

+0

好奇心が強い、2番目の等価操作をしないで、if(!errorCode32.Equals(errorTimeout))と書いてみましたか? –

+0

はいブライアン - 私は試しました。 "return"文は、 "if(false)"を文字通り書き込む場合にのみ実行されます。それ以外の場合、ifは正しく動作しません。 1つの追加のこと - if文がtrueの場合、ifの全内容が実行されます。文が偽(任意の計算によって)の場合、アプリケーションは内部に入り、return/throwのみを実行します。 –

答えて

0

私は問題を調査するのに多くの時間を費やしました。私はいくつかの誤った仮定をしたことを認めなければならないことを意味しても、私が共有したいと思ういくつかの結論を持っています。動作。

まず、私が提示したコードは、サードパーティのライブラリを使用しているときのいくつかの特定の問題を処理することを目的としていました。これらの図書館の文書化されていない振る舞いは、ある状況ではいくつかの条件で例外をスローするというものでした。元の問題は事実から来て、そのライブラリは、我々は

第2のエラー状況を「扱い」しても、例外をthrowed:デバッグ時、私は次のような状況が見つかりました:

1 if (someVariable) 
2 { 
3  someCode(); 
4  someOtherCode(); 
5  throw someExceptionPassedFromTheThirdPartyLibrary; 
6 } 
7 somethingElse(); 

デバッガは行1で停止し、someVariableが偽で、ステップデバッガは5行目で待っています。ここで私は最初の誤った仮定をしました。つまり、ここから例外がスローされます。

3番目:実験を開始しました。 "someVariable"は常にfalseでしたが、デバッガが1行目から7行目、時には1から5行目にスキップされることがありました。私は逆アセンブラを使用することにしました。

第4回:逆アセンブルされたコードの動作を理解することができず、if文が正しく動作しないという考えに固執しました。さらに、私は記事 "http://stackoverflow.com/questions/6054987/if-statement-appears-to-be-evaluating-even-when-condition-evaluates-to-false" [確認されたJITのバグ]が見つかりませんでした今回私を助けました。

私は、いくつかの追加の背景の後、実際に自分のコードで何が起こったのかを説明する時が来たと思います。

一般に私の状況では、 "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オフセットにおける命令の実行(おそらく予測をジャンプ場所、またはいくつかの他のコアプロセッサの最適化を要します)。したがって、3つの命令を呼び出す代わりに、プロセッサはすべてを1つのステップで実行しました。 00000107で比較すべき値が等しくないため、プロセッサは00000134にジャンプしました。この時点で私はここで実際に何が起こっているのか理解できませんでした。そこで、私は単に "return"命令を実行すると仮定しました。真実はシンプルです。 "return 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デバッガでのみです。さらに、バグは実際にはただのものであり、デバッグされたコードに影響を与えないため、重要ではありません。

2

あなたが最適化を有効にしている、とコンパイラはif文の中のreturn文とを組み合わせました関数の最後にあるもの。 2つは同じアドレスを持っていますが、デバッガは一致するので、強調表示するソースコードの行を特定できません。

何も問題はありません。しかし、デバッガを正常に実行するためには、最適化を無効にする必要があります。

これは、オプティマイザがデバッガを混乱させるために行うことのできる1つのみです。他の可能性は、データ依存性(パイプラインを最適化する)を持たない命令を並べ替えたり、命令を分割して別の命令文を間に入れたりすることも可能です。

+0

いいえ、最適化は無効です。さらに、コードを最適化すれば、逆アセンブルされたコードの違いを見ることができます。 –

+0

ええ、35と4fとの間のコードと "mov [ebp-48]、0"と繰り返し "xor edx、edx"は、おそらく無効化されたoptmizationsまたは非常に標準化されていないオプティマイザを指しています。私が言う後者の場合:すぐに新しいコンパイラを入手してください! –

関連する問題