Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CheckInterfaces is too permissive and not permissive enough #96436

Closed
MichalStrehovsky opened this issue Jan 3, 2024 · 1 comment · Fixed by #96805
Closed

CheckInterfaces is too permissive and not permissive enough #96436

MichalStrehovsky opened this issue Jan 3, 2024 · 1 comment · Fixed by #96805

Comments

@MichalStrehovsky
Copy link
Member

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 });
        }
    }
}
@ghost
Copy link

ghost commented Jan 3, 2024

Tagging subscribers to this area: @dotnet/area-system-reflection-emit
See info in area-owners.md if you want to be subscribed.

Issue Details

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 });
        }
    }
}
Author: MichalStrehovsky
Assignees: -
Labels:

area-System.Reflection.Emit

Milestone: -

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jan 3, 2024
@buyaa-n buyaa-n added this to the 9.0.0 milestone Jan 4, 2024
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Jan 4, 2024
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jan 10, 2024
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jan 19, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Feb 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants