Skip to content

CheckInterfaces is too permissive and not permissive enough #96436

Closed
@MichalStrehovsky

Description

@MichalStrehovsky

Ref: #96327 (comment)

Cc @buyaa-n

Notice that CreateType1 works with ref.emit, but throws an exception in the persistable implementation (the checks incorrectly demand an interface method with a default implementation to be implemented).
Similarly, CreateType2 throws with ref.emit, but works with the persistable implementation (the check fails to notice a static abstract method wasn't implemented).

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

namespace TestApp
{
    public interface IFoo
    {
        void Method() => Console.WriteLine("Hello");
    }

    public interface IBar
    {
        static abstract void Method();
    }

    internal class Program
    {
        static Type CreateType1(ModuleBuilder moduleBuilder)
        {
            TypeBuilder t = moduleBuilder.DefineType("TestClass1", TypeAttributes.Class, typeof(object), new Type[] { typeof(IFoo) });

            ConstructorBuilder cb = t.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
            ILGenerator ilgen = cb.GetILGenerator();
            ilgen.Emit(OpCodes.Ret);
            return t.CreateType();
        }

        static Type CreateType2(ModuleBuilder moduleBuilder)
        {
            TypeBuilder t = moduleBuilder.DefineType("TestClass2", TypeAttributes.Class, typeof(object), new Type[] { typeof(IBar) });

            ConstructorBuilder cb = t.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
            ILGenerator ilgen = cb.GetILGenerator();
            ilgen.Emit(OpCodes.Ret);
            return t.CreateType();
        }

        static void Main(string[] args)
        {
            AssemblyName aName = new AssemblyName("MyAssembly");

            AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = ab.DefineDynamicModule("ModuleName"); // Only one module supported

            {
                var t = CreateType1(moduleBuilder);
                var o = Activator.CreateInstance(t);
                Console.WriteLine($"Created type {o.GetType()}");
            }

            try
            {
                var t = CreateType2(moduleBuilder);
                var o = Activator.CreateInstance(t);
                Console.WriteLine(o.GetType());
            }
            catch (TypeLoadException e)
            {
                Console.WriteLine(e.Message);
            }

            ab = PopulateAssemblyBuilderAndSaveMethod(aName, null, out MethodInfo saveMethod);
            moduleBuilder = ab.DefineDynamicModule("ModuleName"); // Only one module supported

            try
            {
                var t = CreateType1(moduleBuilder);
                Console.WriteLine($"Created type {t}");
            }
            catch (TypeLoadException e)
            {
                Console.WriteLine(e.Message);
            }

            {
                var t = CreateType2(moduleBuilder);
                Console.WriteLine(t);
            }

            // Then save the assembly into a file (or Stream)
            saveMethod.Invoke(ab, new object[] { "MyAssembly.dll" });
        }

        private static AssemblyBuilder PopulateAssemblyBuilderAndSaveMethod(AssemblyName assemblyName,
                List<CustomAttributeBuilder> assemblyAttributes, out MethodInfo saveMethod)
        {
            Type abType= Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!;

            saveMethod = abType.GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance,
                                         new Type[] { typeof(string) /* or use typeof(Stream) */ });

            MethodInfo defineDynamicAssembly = abType.GetMethod("DefinePersistedAssembly", BindingFlags.NonPublic | BindingFlags.Static,
                new Type[] { typeof(AssemblyName), typeof(Assembly), typeof(List<CustomAttributeBuilder>) });

            return (AssemblyBuilder)defineDynamicAssembly.Invoke(null, new object[] { assemblyName, typeof(object).Assembly, assemblyAttributes });
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions