Skip to content

CheckInterfaces is too permissive and not permissive enough #96436

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 });
        }
    }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions