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

Reply via email to