跳过不带 DynamicMethod 的动态生成方法的可见性检查
Skip visibility checks for dynamically generated methods without DynamicMethod
这个问题与另外两个问题非常相似:first, second。然而,至少可以说这些已经过时了,我希望 .Net 5 有所改变。
现在首先让我澄清一下这个问题。通过一个简单的示例,尝试获取 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[]>));
这工作得很好,因为我可以告诉 DynamicMethod
跳过可见性检查(即使它工作得很好,当 DynamicMethod
构造函数的最后一个参数 true
已删除)。
但是,当我尝试对下面的示例执行相同操作时,它会抛出 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)' to access field 'System.Collections.Generic.List'1<System.Int32>._items' failed. + GetUnderlyingArrayClass.GetUnderlyingArray(List)
Here is a .Net fiddle link with the code shown above.
现在,我提到的问题之一指向以下属性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。
这就是我感到困惑的地方。将 skipVisibility
参数设置为 true
或 false
实际上并不重要。我假设这是因为我是 运行 .Net 5 环境中的代码。但是,如果 .Net 5 不支持 CAS,为什么我仍然能够读出私有字段?
目标显然是使用 DefineType
/DefineMethod
API 的动态生成方法访问私有 field/method。
我仍然无法解释为什么将 skipVisibility
参数设置为 true
/false
无关紧要,但是 PathogenDavid over on the GitHub from the csharp runtime discussion repository 向我展示了一个解决方案比预期的要容易得多。
// Add IgnoresAccessChecksTo attribute
var ignoresAccessChecksTo = new CustomAttributeBuilder
(
typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] { typeof(string) }),
new object[] { typeof(List<>).Assembly.GetName().Name }
);
assemblyBuilder.SetCustomAttribute(ignoresAccessChecksTo);
请参阅 this .Net Fiddle 以获取工作示例。
正如他所说,IgnoresAccessChecksTo
属性用于绕过检查。
The runtime understands the attribute, but it is not defined in the BCL so you have to define it yourself.
这个问题与另外两个问题非常相似:first, second。然而,至少可以说这些已经过时了,我希望 .Net 5 有所改变。
现在首先让我澄清一下这个问题。通过一个简单的示例,尝试获取 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[]>));
这工作得很好,因为我可以告诉 DynamicMethod
跳过可见性检查(即使它工作得很好,当 DynamicMethod
构造函数的最后一个参数 true
已删除)。
但是,当我尝试对下面的示例执行相同操作时,它会抛出 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)' to access field 'System.Collections.Generic.List'1<System.Int32>._items' failed. + GetUnderlyingArrayClass.GetUnderlyingArray(List)
Here is a .Net fiddle link with the code shown above.
现在,我提到的问题之一指向以下属性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。
这就是我感到困惑的地方。将 skipVisibility
参数设置为 true
或 false
实际上并不重要。我假设这是因为我是 运行 .Net 5 环境中的代码。但是,如果 .Net 5 不支持 CAS,为什么我仍然能够读出私有字段?
目标显然是使用 DefineType
/DefineMethod
API 的动态生成方法访问私有 field/method。
我仍然无法解释为什么将 skipVisibility
参数设置为 true
/false
无关紧要,但是 PathogenDavid over on the GitHub from the csharp runtime discussion repository 向我展示了一个解决方案比预期的要容易得多。
// Add IgnoresAccessChecksTo attribute
var ignoresAccessChecksTo = new CustomAttributeBuilder
(
typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] { typeof(string) }),
new object[] { typeof(List<>).Assembly.GetName().Name }
);
assemblyBuilder.SetCustomAttribute(ignoresAccessChecksTo);
请参阅 this .Net Fiddle 以获取工作示例。
正如他所说,IgnoresAccessChecksTo
属性用于绕过检查。
The runtime understands the attribute, but it is not defined in the BCL so you have to define it yourself.