Skip to content

[mono][System.Reflection.Emit] VTable initialization failure for class implementing an interface #94490

Closed

Description

When using System.Reflection.Emit with Mono, using MethodBuilder.SetReturnType and MethodBuilder.SetParameters on methods that are supposed to implement interface methods does not work - the method is not considered to implement the interface method. Using the long form of TypeBuilder.DefineMethod works.

using System;
using System.Reflection;
using System.Reflection.Emit;

public interface IStr
{
    public string MStr(string x);
}

public class P {
    public static void Main()
    {
        var aname = "TestAssembly";
        var assemblyName = new AssemblyName(aname);
        var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule(aname);

        var typeBuilder = moduleBuilder.DefineType("TestType", TypeAttributes.Public, typeof(object), new Type[] { typeof(IStr) });

#if false
        //works
        var methodBuilder = typeBuilder.DefineMethod("MStr", MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), new Type[] { typeof(string) });
#else
        // throws "Invalid VTable" from CreateInstance, below
        var methodBuilder = typeBuilder.DefineMethod("MStr", MethodAttributes.Public | MethodAttributes.Virtual);
        methodBuilder.SetReturnType(typeof(string));
        methodBuilder.SetParameters(new Type[] { typeof(string) });
#endif

        var ilg = methodBuilder.GetILGenerator();
        ilg.Emit(OpCodes.Ldarg_1);
        ilg.Emit(OpCodes.Ret);

        var type = typeBuilder.CreateType();
        var obj = Activator.CreateInstance(type);
        var m = type.GetMethod("MStr");
        var r = m.Invoke(obj, new object[] { "hello" });
        Console.WriteLine($"r = {r}");
    }
}

Update simpler repro and better diagnosis; original issue below


Needs some investigation still. Some of the System.Reflection.Emit code generates a class with a bad vtable on net8.0.

The TypedClientBuilder is from aspnetcore:

https://github.com/dotnet/aspnetcore/blob/556f39af49b1a32f14089d3809557825932e4ca5/src/SignalR/server/Core/src/Internal/TypedClientBuilder.cs#L49

Repro:

Clone this repo https://github.com/lambdageek/repro-iclientproxy-vtable-fail

Expected

$ dotnet run
SendCoreAsync - M1

Actual

$ dotnet run
Unhandled Exception:
System.TypeLoadException: VTable setup of type Microsoft.AspNetCore.SignalR.TypedClientBuilder.I1Impl failed
   at System.RuntimeType.GetMethodsByName(String name, BindingFlags bindingAttr, MemberListType listType, RuntimeType reflectedType)
   at System.RuntimeType.GetMethodCandidates(String name, BindingFlags bindingAttr, CallingConventions callConv, Type[] types, Int32 genericParamCount, Boolean allowPrefixLookup)
   at System.RuntimeType.GetMethodImpl(String name, Int32 genericParamCount, BindingFlags bindingAttr, Binder binder, CallingConventions callConv, Type[] types, ParameterModifier[] modifiers)
   at System.RuntimeType.GetMethodImpl(String name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
   at System.Type.GetMethod(String name, BindingFlags bindingAttr)
   at Retrofit.TypedClientBuilder`1[[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].GenerateClientBuilder() in /private/tmp/promo/TypedClientBuilder.cs:line 42
   at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].CreateValue()
   at System.Lazy`1[[System.Func`2[[Retrofit.IClientProxy, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].get_Value()
   at Retrofit.TypedClientBuilder`1[[I1, promo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Build(IClientProxy proxy) in /private/tmp/promo/TypedClientBuilder.cs:line 24
   at P.Main() in /private/tmp/promo/Program.cs:line 19
   at P.<Main>()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions