Understand MSIL about trying to finally catch

I have the following code

using System; class Pankaj { public static int Main() { int returnValue=0; try { return returnValue; throw new Exception(); } catch(Exception ex){ return returnValue; } finally { returnValue++; } return returnValue; } } 

MSIL generated by the above code:

 .method public hidebysig static int32 Main() cil managed { .entrypoint // Code size 18 (0x12) .maxstack 2 .locals init (int32 V_0, int32 V_1) IL_0000: ldc.i4.0 IL_0001: stloc.0 .try { .try { IL_0002: ldloc.0 IL_0003: stloc.1 IL_0004: leave.s IL_0010 } // end .try catch [mscorlib]System.Exception { IL_0006: pop IL_0007: ldloc.0 IL_0008: stloc.1 IL_0009: leave.s IL_0010 } // end handler } // end .try finally { IL_000b: ldloc.0 IL_000c: ldc.i4.1 IL_000d: add IL_000e: stloc.0 IL_000f: endfinally } // end handler IL_0010: ldloc.1 IL_0011: ret } // end of method Pankaj::Main 

I have the following questions:

  • Why try catch is included again inside the try block.
  • It seems that left.s last line in the try and catch block finally points to IL_0010 but in line IL_0010 its ldloc.1, which, I believe, means loading local variable 1 on the stack, then how to point it to the final block. This is something like location 1, we have the address of the finally block.
  • If I drop or return something from the catch block, then how it turns out that the call statement falls on the finally block, it already returns from the catch block, but still the finally block is executed.
+8
c # cil il
source share
2 answers

Why is the try catch attempt turned on again inside the try block.

Not sure about that. It may be that ildasm decides to decompile it. ECMA-335 says that there are restrictions on how SEHClause elements can be specified after TryBlock , but I have not found these restrictions yet.

It seems that left.s last line in the try and catch block finally indicates that IL_0010, but in line IL_0010 its ldloc.1, which, I believe, means loading local variable 1 on the stack, while pointing to final block, This is something like in location 1, we have the address of the finally block.

No, that jumps after the finally block - to effectively return the value. This does not help that you have many return statements returning the same thing, as well as unreachable code, but I believe that in principle, just moving ret outside of try and catch . I think the compiler efficiently sets up an additional local variable for the return value.

If I drop or return something from the catch block, then how it turns out that the call statement falls to the finally block, it already returns from the catch block, but still the finally block is executed.

Both C # and IL are defined - the finally block will be executed, but you exit the block.

+10
source share
John Skeet has already answered the last two questions, so I just focus on the first.

Why is the try catch attempt turned on again inside the try block.

There are several reasons for this:

  • Placing the catch handler inside the try block associated with the finally handler means that it will finally happen even if an exception is thrown inside the catch block (which I think is required by the C # specification), although I don't have a direct indication of where it says).
  • The CLI specification contains some strict rules on overlapping areas of exception handling, and these rules preclude the possibility of locking catch and finally from protecting the same code without the finally block protecting the catch block or the catch block also protecting the finally block (The specification discusses it in in more general terms than this, you can find details in section 1, section 12.4.2.7 of ECMA-335).
+2
source share

All Articles