PEVerify fails on explicit interface property when the interface is in a Portable Class Library

0

I'm emitting a class that explicitly implements a simple interface property with a get method. There are no problems so long as the interface is not defined in a portable class library. However, when moving the interface to a PCL and using only specific types such as IEnumerable<int>, PEVerify will fail.

Looking at ILDASM -> MetaInfo -> Show, you would see that both mscorlib and System.Runtime assembly references are imported. This occurs during the call to DefineMethodOverride (watch AssemblyBuilder.GetReferencedAssemblies() to see). You can also see that IEnumerable`1 is brought in as a TypeRef from both assemblies, which seems to be the problem.

When not separating the interface to a PCL, or when changing the type to something else, it works and the System.Runtime reference is not included. To try string, replace IEnumerable<int> with string in the interface as well as DefineProperty/DefineMethod calls.

Using a modified example from MSDN as a simplified way to reproduce this issue, drop the code below in a console project and everything works great. Move interface I to a portable class library project and you will see exactly what I mean.

How can I get rid of the PEVerify error?

Error: MethodImpl's Decl (token=0x0a000001) and Body (token=0x00610072) method signatures do not match. [token:0x19000001] [hr:0x801312F4]

public interface I
{
    IEnumerable<int> E { get; }
}

class Test
{
    static void Main()
    {
        string name = "DefineMethodOverrideExample";
        AssemblyName asmName = new AssemblyName(name);
        AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder mb = ab.DefineDynamicModule(name, name + ".dll");
        TypeBuilder tb = mb.DefineType("C", TypeAttributes.Public);
        tb.AddInterfaceImplementation(typeof(I));

        PropertyBuilder prop = tb.DefineProperty("I.E", PropertyAttributes.None, typeof(IEnumerable<int>), Type.EmptyTypes);

        MethodBuilder mbIM = tb.DefineMethod(
            "I.get_E",
            MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.SpecialName,
            typeof(IEnumerable<int>),
            Type.EmptyTypes);
        prop.SetGetMethod(mbIM);

        ILGenerator il = mbIM.GetILGenerator();
        il.Emit(OpCodes.Ldnull);
        il.Emit(OpCodes.Ret);

        tb.DefineMethodOverride(mbIM, typeof(I).GetProperty("E").GetGetMethod());

        Type tc = tb.CreateType();

        ab.Save(name + ".dll");
    }
}

(.Net 4.5.1)

(PEVerify and ILDASM versions 4.0.30319.33440 from C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\x64)

Thanks!

c#
reflection.emit
peverify
asked on Stack Overflow Feb 3, 2015 by Eric

1 Answer

0

After doing some more comparisons with emitted and compiled examples, as well as digging into the .NET libraries, I was able to discover the key distinction was in the call to ModuleBuilder.DefineMethodOverrideNoLock -> GetMethodTokenInternalNoLock (on the interface), in where there is a test for whether the provided MethodInfo is a RuntimeMethodInfo. Ultimately a call to GetMemberRefOfMethodInfo causes the inclusion of System.Runtime, producing conflicting results for certain types, such as IEnumerable.

To solve this in a manner that doesn't require reflecting into private members, you can create a proxy or wrapper that inherits MethodInfo which overrides all methods to return results from the original RuntimeMethodInfo. This will cause the ILDASM to show the TypeRef and TypeSpec elements that appear in a compiled (non-emitted) assembly trying to explicitly implement a PCL interface method. I was able to successfully verify an emitted assembly using this technique.

answered on Stack Overflow Feb 4, 2015 by Eric

User contributions licensed under CC BY-SA 3.0