NullReferenceException与MSIL

我正在解释来自C#Windows Phone应用程序的异常报告。 一个方法抛出一个NullReferenceException 。 该方法是:

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为空是一致的 - 除此之外,没有其他可能是空的。 但这是神秘的部分。

来自StackTraceStackFrame的异常对象的GetILOffset()返回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也可以抛出,但只有当this对象为null时才会抛出; 这在C#AFAIK中是不可能的。

文档提到调试信息可能会影响偏移量,但它是一个发布版本。

我正在使用ILDASM检查的DLL正是我作为XAP的一部分发往Windows Phone商店的DLL。


当JIT生成机器码时,它也会生成MSIL < - >机器码映射。 当您在生成的代码中遇到异常时,运行时将使用映射来识别IL偏移量。

允许JIT将机器指令作为其优化的一部分进行重新排序(当它们启用时),这可能导致映射变得更加接近和细化。 如果字段访问被提出(内存访问相对较慢,有时在你需要它之​​前开始加载它的好处),那么这个异常可能看起来是由早期的IL指令引发的。


我屠杀了我的一个调试工具来执行以下操作:

  • 启动一个目标进程并运行,直到出现异常
  • 捕获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.0ldfldcallvirt指令全部由相同的映射覆盖,所以如果其中任何一个触发异常,它们将全部映射回相同的IL偏移量(0x13)。

    链接地址: http://www.djcxy.com/p/33521.html

    上一篇: NullReferenceException vs. MSIL

    下一篇: Timeout feature in the axios library is not working