Share via

Skip visibility checks for dynamically generated methods without DynamicMethod

Twenty 1 Reputation point
2021-02-08T18:55:48.723+00:00

This question is very similar to a two other questions see: first, second. However those are pretty out dated to say the least and I hope things have changed with .Net 5.

Now first up let me clarify the issue. With a simple example that tries to get the underlying array of a List<int>.

var method = new DynamicMethod("GetUnderlyingArray", typeof(int[]), new[] { typeof(List<int>) }, typeof(List<int>), true);  
  
var ilGenerator = method.GetILGenerator();  
  
ilGenerator.Emit(OpCodes.Ldarg_0);  
ilGenerator.Emit(OpCodes.Ldfld, typeof(List<int>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance));  
ilGenerator.Emit(OpCodes.Ret);  
  
var arrayGetter = (Func<List<int>, int[]>)method.CreateDelegate(typeof(Func<List<int>, int[]>));  

This works perfectly fine as I am able to tell the DynamicMethod to skip the visibility checks (even though it works as well, when the last parameter of the DynamicMethod constructor true is removed).

However, when I am trying to do the same with the example down below, it will throw a FieldAccessException.

var assemblyName = new AssemblyName("Example");  
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);  
var dynamicModule = assemblyBuilder.DefineDynamicModule(assemblyName.Name + ".dll");  
  
var type = dynamicModule.DefineType("GetUnderlyingArrayClass");  
  
var method = type.DefineMethod("GetUnderlyingArray", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, typeof(int[]), new[] { typeof(List<int>) });  
  
var ilGenerator = method.GetILGenerator();  
ilGenerator.Emit(OpCodes.Ldarg_0);  
ilGenerator.Emit(OpCodes.Ldfld, typeof(List<int>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance));  
ilGenerator.Emit(OpCodes.Ret);  
  
type.CreateType();  
  
var arrayGetter = (Func<List<int>, int[]>)type.GetMethod("GetUnderlyingArray").CreateDelegate(typeof(Func<List<int>, int[]>));  

System.FieldAccessException: Attempt by method 'GetUnderlyingArrayClass.GetUnderlyingArray(System.Collections.Generic.List'1<Int32>)' to access field 'System.Collections.Generic.List'1<System.Int32>._items' failed. + GetUnderlyingArrayClass.GetUnderlyingArray(List<int>)

Here is a .Net fiddle link with the code shown above.

Now, one of the questions I mentioned points to the following attribute ReflectionPermissionAttribute. However as it states on the documentation Code Access Security is not supported or honored by the runtime.. From what I understand, this basically means that .Net Core/.Net 5 do not support CAS.

Here is where I am getting confused. Setting the skipVisibility parameter to true or false doesn't actually matter. I'd assume that is due to the fact that I am running the code in a .Net 5 environment. However, if CAS is not supported on .Net 5, why am I still able to read out the private field?

The goal is obviously to access a private field/method from a dynamically generated method using the DefineType/DefineMethod API's.

Developer technologies | C#
Developer technologies | C#

An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.