簡體   English   中英

在異常塊之前是否需要空的評估堆棧?

[英]Is an empty evaluation stack required before an exception block?

當我刪除Ldstr "a"Call Console.WriteLine (在Ret之前)時,代碼運行正常,否則在調用時拋出InvalidProgramException 這是否意味着需要一個空的評估堆棧?

class Program
{
    delegate void Del();

    static void Main(string[] args)
    {
        DynamicMethod dynamicMethod = new DynamicMethod("", null, Type.EmptyTypes);
        ILGenerator ilGen = dynamicMethod.GetILGenerator();
        ilGen.Emit(OpCodes.Ldstr, "a");

        ilGen.BeginExceptionBlock();
        ilGen.Emit(OpCodes.Ldstr, "b");
        ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null));
        ilGen.BeginCatchBlock(typeof(Exception));
        ilGen.EndExceptionBlock();

        ilGen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null));
        ilGen.Emit(OpCodes.Ret);

        ((Del)dynamicMethod.CreateDelegate(typeof(Del))).Invoke();
    }
}

為了理解你在做什么,我建議你盡可能做一個最小的例子。

ilGen.Emit(OpCodes.Ldstr, "a");

ilGen.BeginExceptionBlock();
ilGen.BeginCatchBlock(typeof(Exception));
ilGen.EndExceptionBlock();

ilGen.Emit(OpCodes.Pop);
ilGen.Emit(OpCodes.Ret);

之后,您可以使用AssemblyBuilder將給定代碼轉儲到可執行文件中。 如果完成, ildasm將顯示已生成的內容。

// Code size       17 (0x11)
  .maxstack  2
  IL_0000:  ldstr      "a"
  .try
  {
    IL_0005:  leave      IL_000f
  }  // end .try
  catch [mscorlib]System.Exception 
  {
    IL_000a:  leave      IL_000f
  }  // end handler
  IL_000f:  pop
  IL_0010:  ret

正如您所看到的,我們將達到跳轉到popleave指令。 然后你可以谷歌關於leave ,其中說明:

leave指令類似於br指令,但它可用於退出try,filter或catch塊,而普通分支指令只能在這樣的塊中用於在其中傳輸控制。 leave指令清空評估堆棧並確保執行適當的周圍finally塊。

但是,為什么以下的工作沒有呢?

ilGen.Emit(OpCodes.Ldstr, "a");

ilGen.BeginExceptionBlock();
ilGen.BeginCatchBlock(typeof(Exception));
ilGen.EndExceptionBlock();

//ilGen.Emit(OpCodes.Pop);
ilGen.Emit(OpCodes.Ret);

我懷疑它可能不是“物理限制”,而是驗證問題。 讓我們運行peverify ourapp.exe ,看看我們得到了什么:

[IL]: Error: [C:\temp\test.exe : Program::Main][offset 0x00000005] Attempt to en
ter a try block with nonempty stack.
1 Error(s) Verifying C:\temp\test.exe

在這一點上,你可能會像,掃管笏? 通過一點谷歌搜索,你可以得到一個錯誤代碼0x801318A9 通過SSCLI2.0快速掃描來源:

case ReaderBaseNS::RGN_TRY:
    // Entering a try region, the evaluation stack is required to be empty.
    if (!m_readerStack->empty()) {
        BADCODE(MVER_E_TRY_N_EMPTY_STACK);                    
    }
    break;

現在,這很酷,但如果你很討厭,你可能想知道為什么評估堆棧必須是空的?

為此,您可能希望了解ECMA C#和公共語言基礎結構標准 我懷疑你可以從PartitionIII CIL.pdf中找到原因

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM