Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Current dynamic method implementation does not have built-in support to pre-check whether the dynamic method code is verifiable. With bad IL sequence, very often you will get "System.InvalidProgramException: Common Language Runtime detected an invalid program" when it gets executed. See the code example below, where C1, C2 are 2 simple reference types. Btw I understand only me write such "fun" IL code.
LocalBuilder lb = ilgen.DeclareLocal(typeof(C2));
ilgen.Emit(OpCodes.Newobj, typeof(C1).GetConstructor(Type.EmptyTypes));
ilgen.Emit(OpCodes.Stloc_0, lb);
ilgen.Emit(OpCodes.Ldc_I4_0);
ilgen.EmitWriteLine("I got called");
ilgen.Emit(OpCodes.Ret);
Even if you did not get InvalidProgramException, it does not mean the code-gen is correct. When the following code get invoked, "I got called too" will be printed; but the code is not verifiable. When the SkipVerification permission is refused, executing this dynamic method causes JIT to verify first: "System.Security.VerficationException: Operation could destabilize the runtime" throws.
LocalBuilder lb = ilgen.DeclareLocal(typeof(C2));
ilgen.Emit(OpCodes.Newobj, typeof(C1).GetConstructor(Type.EmptyTypes));
ilgen.Emit(OpCodes.Stloc_0, lb);
ilgen.EmitWriteLine("I got called too");
ilgen.Emit(OpCodes.Ret);
However both exception messages contain no much useful information: they do not tell which instruction could be blamed. For any production code using DynamicMethod, to ensure the code-gen quality, it is a good practice to have another implementation which have Reflection.Emit to emit the same IL code to disk, and call Peverify.exe to verify it. IronPython's code-gen has both approaches: at the beginning when we enforced this check, we caught several code-gen issues. This is what peverify.exe shows for the 2 scenarios above:
[IL]: Error: [D:\snippets.dll : Sample::M][offset 0x00000005][found ref 'C1'][expected ref 'C2'] Unexpected type on the stack.
[IL]: Error: [D:\snippets.dll : Sample::M][offset 0x00000011] Stack must be empty on return from a void function.
----
[IL]: Error: [D:\snippets.dll : Sample::M][offset 0x00000005][found ref 'C1'][expected ref 'C2'] Unexpected type on the stack.