I've been pointed to something strange I'd like to confirm as a bug before reporting it on MS Connect: when using the ldtoken IL instruction on a method token in a specific scenario, I get unverifiable code, although a callvirt instruction on the same method token is verifiable.
Consider the following program (C#; IL should be attached to this message if the list lets it through): using System; using System.Collections.Generic; class Program { static void Main () { new Implementer ().GenericTestMethod (new List<string> ()); } } public interface GenericTestInterface<T> where T : IEnumerable<string> { string GenericTestMethod<T2> (T2 obj) where T2 : T; } public class Implementer : GenericTestInterface<List<string>> { public string GenericTestMethod<T2> (T2 obj) where T2: List<string> { GenericTestInterface<List<string>> ifc = this; return ifc.GenericTestMethod<T2> (null); } } When compiling and disassembling this program, Implementer.GenericTestMethod contains the following IL code (line 108): IL_000d: callvirt instance string class GenericTestInterface`1<class [mscorlib]System.Collections.Generic.List`1<string>>::GenericTestMethod<!!0>(!!0) This is verifiable and works without any problems (i.e. running the program yields a StackOverflowException, as expected). Now add a ldtoken instruction for the same method: IL_000d: callvirt instance string class GenericTestInterface`1<class [mscorlib]System.Collections.Generic.List`1<string>>::GenericTestMethod<!!0>(!!0) ldtoken method instance string class GenericTestInterface`1<class [mscorlib]System.Collections.Generic.List`1<string>>::GenericTestMethod<!!0>(!!0) pop This will lead to a verification error: [IL]: Error: [C:\Documents and Settings\fabian.schmied\Desktop\Temp\ConsoleApplication19\ConsoleApplication19\bin\Debug\test.exe : Implementer::GenericTestMethod[T2]][offset 0x00000012][token 0x2B000001]System.Security.VerificationException: Method GenericTestInterface`1[System.Collections.Generic.List`1[System.String]].GenericTestMethod: type argument 'T2' violates the constraint of type parameter 'T2'. [HRESULT 0x8013150D] I don't believe this error is correct. First, the implementer's T2 doesn't violate the constraint of the interface's T2. Second, if I can use a callvirt on the token, I should also be able to use ldtoken on it, right? (ILDASM's "Show token values"/"Show bytes" options confirm that the same token is used in both instructions.) Any thoughts on this? Fabian =================================== This list is hosted by DevelopMentorĀ® http://www.develop.com View archives and manage your subscription(s) at http://discuss.develop.com
// Microsoft (R) .NET Framework IL Disassembler. Version 2.0.50727.42 // Copyright (c) Microsoft Corporation. All rights reserved. // Metadata version: v2.0.50727 .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 2:0:0:0 } .assembly ConsoleApplication19 { .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0.. .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 30 64 65 64 61 65 38 32 2D 62 66 33 62 // ..$0dedae82-bf3b 2D 34 64 64 33 2D 62 39 35 61 2D 30 65 65 63 66 // -4dd3-b95a-0eecf 30 32 32 33 31 31 30 00 00 ) // 0223110.. .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 19 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright .. 72 75 62 69 63 6F 6E 20 32 30 30 37 00 00 ) // rubicon 2007.. .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 14 43 6F 6E 73 6F 6C 65 41 70 70 6C 69 63 // ...ConsoleApplic 61 74 69 6F 6E 31 39 00 00 ) // ation19.. .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 07 72 75 62 69 63 6F 6E 00 00 ) // ...rubicon.. .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 14 43 6F 6E 73 6F 6C 65 41 70 70 6C 69 63 // ...ConsoleApplic 61 74 69 6F 6E 31 39 00 00 ) // ation19.. // --- The following custom attribute is added automatically, do not uncomment ------- // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. .hash algorithm 0x00008004 .ver 1:0:0:0 } .module ConsoleApplication19.exe // MVID: {068A4D44-AF06-4F74-B228-2168ED80EA64} .imagebase 0x00400000 .file alignment 0x00001000 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY // Image base: 0x03050000 // =============== CLASS MEMBERS DECLARATION =================== .class private auto ansi beforefieldinit Program extends [mscorlib]System.Object { .method private hidebysig static void Main() cil managed { .entrypoint // Code size 18 (0x12) .maxstack 8 IL_0000: nop IL_0001: newobj instance void Implementer::.ctor() IL_0006: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor() IL_000b: call instance string Implementer::GenericTestMethod<class [mscorlib]System.Collections.Generic.List`1<string>>(!!0) IL_0010: pop IL_0011: ret } // end of method Program::Main .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Program::.ctor } // end of class Program .class interface public abstract auto ansi GenericTestInterface`1<(class [mscorlib]System.Collections.Generic.IEnumerable`1<string>) T> { .method public hidebysig newslot abstract virtual instance string GenericTestMethod<(!T) T2>(!!T2 obj) cil managed { } // end of method GenericTestInterface`1::GenericTestMethod } // end of class GenericTestInterface`1 .class public auto ansi beforefieldinit Implementer extends [mscorlib]System.Object implements class GenericTestInterface`1<class [mscorlib]System.Collections.Generic.List`1<string>> { .method public hidebysig newslot virtual final instance string GenericTestMethod<(class [mscorlib]System.Collections.Generic.List`1<string>) T2>(!!T2 obj) cil managed { // Code size 23 (0x17) .maxstack 2 .locals init ([0] class GenericTestInterface`1<class [mscorlib]System.Collections.Generic.List`1<string>> ifc, [1] string CS$1$0000, [2] !!T2 CS$0$0001) IL_0000: nop IL_0001: ldarg.0 IL_0002: stloc.0 IL_0003: ldloc.0 IL_0004: ldloca.s CS$0$0001 IL_0006: initobj !!T2 IL_000c: ldloc.2 IL_000d: callvirt instance string class GenericTestInterface`1<class [mscorlib]System.Collections.Generic.List`1<string>>::GenericTestMethod<!!0>(!!0) ldtoken method instance string class GenericTestInterface`1<class [mscorlib]System.Collections.Generic.List`1<string>>::GenericTestMethod<!!0>(!!0) pop IL_0012: stloc.1 IL_0013: br.s IL_0015 IL_0015: ldloc.1 IL_0016: ret } // end of method Implementer::GenericTestMethod .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // end of method Implementer::.ctor } // end of class Implementer // ============================================================= // *********** DISASSEMBLY COMPLETE *********************** // WARNING: Created Win32 resource file test.res