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

InternalsVisibleTo does not work with AssemblyBuilder #12454

Closed
nitroxis opened this issue Apr 9, 2019 · 4 comments
Closed

InternalsVisibleTo does not work with AssemblyBuilder #12454

nitroxis opened this issue Apr 9, 2019 · 4 comments
Assignees
Milestone

Comments

@nitroxis
Copy link

nitroxis commented Apr 9, 2019

It appears that the InternalsVisibleToAttribute does not work when the friend assembly is a dynamic assembly / AssemblyBuilder.

Repro:

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo(Program.AssemblyName)]

static class Program
{
	public const string AssemblyName = "TestAssembly";

	private static int x = 1337;
	
	static void Main(string[] args)
	{
		FieldInfo field = typeof(Program).GetField(nameof(x), BindingFlags.Static | BindingFlags.NonPublic);

		AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(AssemblyName), AssemblyBuilderAccess.Run);

		// Doing this works fine:
		//ConstructorInfo attrCtor = typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] {typeof(string)});
		//assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(attrCtor, new object[] {typeof(Program).Assembly.GetName().Name}));
		
		ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(AssemblyName);
		TypeBuilder typeBuilder = moduleBuilder.DefineType("T", TypeAttributes.Class | TypeAttributes.Public);
		MethodBuilder methodBuilder = typeBuilder.DefineMethod("M", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(int), new Type[0]);
		ILGenerator il = methodBuilder.GetILGenerator();
		il.Emit(OpCodes.Ldsfld, field);
		il.Emit(OpCodes.Ret);

		Type type = typeBuilder.CreateType();
		MethodInfo m = type.GetMethod("M", BindingFlags.Static | BindingFlags.Public);

		int res = (int)m.Invoke(null, new object[0]);
		Console.WriteLine(res);
	}
}

Invoking the method leads to FieldAccessException: Attempt by method 'T.M()' to access field 'Program.x' failed even though internals are visible to that assembly. It also doesn't work when both assemblies (i.e. the one declaring the attribute and the subject of the attribute) are dynamic assemblies. The two commented-out lines adds an IgnoresAccessChecksToAttribute to the dynamic assembly, which seems to work fine. It may be necessary to define that attribute as follows:

namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	public class IgnoresAccessChecksToAttribute : Attribute
	{
		public string AssemblyName { get; }
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
			this.AssemblyName = assemblyName;
		}
	}
}

Am I missing something? Is there a reason why InternalsVisibleTo can not be used with dynamic assemblies? Granted, it is a relatively unusual scenario, but I don't see why it shouldn't work. A possible alternative or additional solution I'd love to see would be to allow disabling access checks altogether when defining a dynamic assembly, just as is possible with DynamicMethod.

@RussKeldorph
Copy link
Contributor

@davidwrighton

@davidwrighton
Copy link
Member

I'd say this is a bug, but I don't know what the priority to fix it would be. I've reproduced the issue locally, but have not root caused it.

@MichalStrehovsky
Copy link
Member

I'm assigning milestones to things in area-TypeSystem in preparation for the 3.0 release. Since this behaves the same on desktop CLR, I'm placing this to the Future milestone.

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@mangod9 mangod9 modified the milestones: Future, 6.0.0 Sep 17, 2020
oskardudycz added a commit to oskardudycz/EventSourcing.NetCore that referenced this issue Dec 6, 2020
oskardudycz added a commit to oskardudycz/EventSourcing.NetCore that referenced this issue Dec 6, 2020
@davidwrighton
Copy link
Member

So, it turns out that I was incorrect in my initial triage of this bug. This test case has a bug. In particular, the x member of the Program class has private visibility not internal visibility. If x were internal, then this test passes. This distinction in behavior is correct, as the InternalsVisibleToAttribute provides access to internal members, not private members. Now, in my investigation, I've see that there are some issues where InternalsVisibleToAttribute when applied to a dynamic assembly may not be respected once there has been an attempt to establish friend visibility to a member on the reflection type, so I will be looking into that for .NET 6.0; however, as this issue is actually a misunderstanding of the spec of InternalsVisibleToAttribute I'm closing this bug.

@ghost ghost locked as resolved and limited conversation to collaborators Mar 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants