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