2016-04-17 21 views
7

私はC#Windows Phoneアプリケーションから例外レポートを解釈しています。メソッドはNullReferenceExceptionをスローします。この方法は、行く:NullReferenceExceptionとMSILとの比較

public void OnDelete(object o, EventArgs a) 
{ 
    if (MessageBox.Show(Res.IDS_AREYOUSURE, Res.IDS_APPTITLE, MessageBoxButton.OKCancel) == MessageBoxResult.OK) 
     m_Field.RequestDelete(); 
} 

それはm_Fieldがnullであることと一致だ - nullの可能性があることができますが他には何も単にありません。しかし、ここで不思議な部分があります。

例外オブジェクトのStackTraceStackFrameGetILOffset()は0x13を返します。 ILDASMで示されているように、メソッドのMSILは次のようになります。

IL_0000: call  string App.Res::get_IDS_AREYOUSURE() 
IL_0005: call  string App.Res::get_IDS_APPTITLE() 
IL_000a: ldc.i4.1 
IL_000b: call  valuetype (...) System.Windows.MessageBox::Show(...) 
IL_0010: ldc.i4.1 
IL_0011: bne.un.s IL_001e 
IL_0013: ldarg.0 
IL_0014: ldfld  class App.Class2 App.Class1::m_Field 
IL_0019: callvirt instance void App.Class2::RequestDelete() 
IL_001e: ret 

これは私が理解できないものです。実際にオフセットが0x13の場合は、ldarg行が例外を引き起こすことを意味します。しかし、このコマンドは例外を投げないこととして文書化されている。 callvirtそれは投げるべきではないですか?または、メソッドの開始以外のオフセットに相対的なオフセットですか? ldfldもスローできますが、オブジェクトがnullの場合にのみthisオブジェクトがスローされます。これはC#AFAIKでは不可能です。

ドキュメントでは、デバッグ情報がオフセットの途中に入るかもしれないと言いますが、リリースビルドです。

ILDASMで検査しているDLLは、XAPの一部としてWindows Phone Storeに出荷されたDLLです。

答えて

3

JITがマシンコードを生成すると、MSIL < - >マシンコードマッピングも生成されます。生成されたコードで例外が発生すると、実行時にマッピングが使用されてILオフセットが識別されます。

JITは、最適化の一部としてマシン命令を並べ替えることができます(有効になっている場合)。これにより、マッピングがより近似して細かくなります。フィールドへのアクセスが先に進んだ場合(メモリアクセスが比較的遅く、必要になる前にロードを開始するのが良い場合もあります)、以前のIL命令で例外がスローされたように見えることがあります。


私は、次の操作を行うために私のデバッグユーティリティの1つを虐殺:例外

  • があるまで

      は& IL-にネイティブのマッピングILバイトをキャプチャするターゲット・プロセスを開始し、実行
    • (厳密に)どのIL命令が同じマッピングでグループ化されているかを示すインジケータでILを逆アセンブルします。
    • 私は、あなたが質問に表示おおよそ何がダミープロセス上のツールを実行し、次の(リリースビルド)を得た

    IL_0000: call 0600000B 
    IL_0005: call 0600000A 
    IL_000A: ldc.i4.1 
    IL_000B: call 0A000014 
    IL_0010: ldc.i4.1 
    IL_0011: bne.un.s 30 
    ---- 
    IL_0013: ldarg.0 
    IL_0014: ldfld 04000001 
    IL_0019: callvirt 06000004 
    ---- 
    IL_001E: ret 
    

    あなたが見ることができるように、ldarg.0ldfldおよびcallvirt命令はすべて同じマッピングでカバーされているため、これらのいずれかが例外をトリガする場合は、すべて同じILオフセット(0x13)にマップされます。

  • +0

    しかし、フィールドアクセス( 'ldfld')ではスローする必要がありません(' this'は 'null'ではないので)、' callvirt'です。分解を見て、私は並べ替えが原因だとは思わない。 – svick

    +0

    フィールドアクセス/並べ替えでの公平な点ですが、マッピングの粒度を小さくすることで説明できると私は考えています。私は実際のマッピングを二重チェックして、結果に戻ってきます。 –

    +0

    @svick、私は再現し、マッピングをチェックし、結果で更新しました。 –

    関連する問題