You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何这段Reflection.Emit代码会引发AccessViolationException?

Reflection.Emit代码触发AccessViolationException的原因及解决方法

通常来说,托管代码不应引发访问冲突,这类问题一般出现在原生代码或unsafe代码中。但一段看似简单的Reflection.Emit代码却触发了AccessViolationException,报错位置在((IEnumerable)sorted).Cast<object>().ToArray();这一行。

问题代码

using System.Collections;
using System.Reflection;
using System.Reflection.Emit;

namespace Repro
{
    internal class Program
    {
        static void Main()
        {
            TypeBuilder typeBuilder = BuildType();

            var realType = typeBuilder.CreateType();
            var arr = Array.CreateInstance(realType, 10);
            var caster = typeof(Enumerable).GetMethod("Cast")!.MakeGenericMethod(realType);
            var typedArr = caster.Invoke(null, [arr]);

            var sorter = realType.GetMethod("Sort")!;
            var sorted = sorter.Invoke(null, [typedArr])!;
            var bomb = ((IEnumerable)sorted).Cast<object>().ToArray(); // 此处触发异常
        }

        private static TypeBuilder BuildType()
        {
            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new("MyAssembly"), AssemblyBuilderAccess.RunAndCollect);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MyAssembly");
            var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public, typeof(ValueType));
            var field = typeBuilder.DefineField("field", typeof(int), FieldAttributes.Public);
            var extractor = typeBuilder.DefineMethod("GetField", MethodAttributes.Private | MethodAttributes.Static, typeof(int), [typeof(int)]);
            var il = extractor.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, field);
            il.Emit(OpCodes.Ret);

            var enumType = typeof(IEnumerable<>).MakeGenericType(typeBuilder);
            var impl = typeBuilder.DefineMethod("Sort", MethodAttributes.Public | MethodAttributes.Static, enumType, [enumType]);
            il = impl.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldtoken, extractor);
            var getMethod = typeof(MethodBase).GetMethod("GetMethodFromHandle", [typeof(RuntimeMethodHandle)])!;
            il.Emit(OpCodes.Call, getMethod);

            var orderFunc = typeof(Enumerable).GetMethods().Single(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
            il.Emit(OpCodes.Call, orderFunc.MakeGenericMethod(typeBuilder, typeof(int))); // 调用Enumerable.OrderBy(enumerable, extractor)
            il.Emit(OpCodes.Ret);
            return typeBuilder;
        }
    }
}

预期等效的原生代码

using System.Linq;

struct MyType
{
   public int field;
   private static int GetField(MyType value) => value.field;

   public static IEnumerable<MyType> Sort(IEnumerable<MyType> values)
   {
      return values.OrderBy(MyType.GetField);
   }
}

// 在Main中
var arr = new MyType[10];
var sorted = MyType.Sort(arr);
var bomb = sorted.ToArray();

原因分析

出现AccessViolationException的核心原因有两个:

  1. GetField方法参数类型错误
    你定义的GetField方法参数类型是int,但实际需要的是动态生成的MyType结构体类型。这导致IL代码中尝试对int类型执行Ldfld操作(访问MyType的field字段),相当于把int的内存当作结构体来解析,直接访问了非法的内存地址,这是触发访问冲突的直接原因。

  2. 传递给OrderBy的参数类型不匹配
    在Sort方法的IL中,你通过MethodBase.GetMethodFromHandle获取了方法的MethodBase实例,但Enumerable.OrderBy需要的是Func<MyType, int>委托类型。直接传递MethodBase对象会导致类型不匹配,运行时调用委托时会出现内存访问错误。

解决方法

修正上述两个错误即可解决问题:

1. 修正GetField方法的参数类型

将GetField方法的参数类型从typeof(int)改为动态生成的typeBuilder(即MyType):

var extractor = typeBuilder.DefineMethod("GetField", MethodAttributes.Private | MethodAttributes.Static, typeof(int), new[] { typeBuilder });

2. 正确创建委托并传递给OrderBy

替换Sort方法中获取MethodBase的代码,改为创建正确的Func<MyType, int>委托:

// 替换原来的Ldtoken和GetMethodFromHandle代码块
il.Emit(OpCodes.Ldnull); // 静态方法,目标对象为null
il.Emit(OpCodes.Ldtoken, extractor);
var methodHandleValueProp = typeof(RuntimeMethodHandle).GetProperty(nameof(RuntimeMethodHandle.Value))!.GetGetMethod();
il.Emit(OpCodes.Call, methodHandleValueProp);
var funcType = typeof(Func<,>).MakeGenericType(typeBuilder, typeof(int));
var createDelegateMethod = typeof(Delegate).GetMethod(nameof(Delegate.CreateDelegate), new[] { typeof(Type), typeof(object), typeof(IntPtr) })!;
il.Emit(OpCodes.Call, createDelegateMethod);

修正后的完整BuildType方法

private static TypeBuilder BuildType()
{
    AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new("MyAssembly"), AssemblyBuilderAccess.RunAndCollect);
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MyAssembly");
    var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public, typeof(ValueType));
    var field = typeBuilder.DefineField("field", typeof(int), FieldAttributes.Public);
    
    // 修正参数类型为typeBuilder
    var extractor = typeBuilder.DefineMethod("GetField", MethodAttributes.Private | MethodAttributes.Static, typeof(int), new[] { typeBuilder });
    var il = extractor.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Ldfld, field);
    il.Emit(OpCodes.Ret);

    var enumType = typeof(IEnumerable<>).MakeGenericType(typeBuilder);
    var impl = typeBuilder.DefineMethod("Sort", MethodAttributes.Public | MethodAttributes.Static, enumType, [enumType]);
    il = impl.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    
    // 正确创建Func委托
    il.Emit(OpCodes.Ldnull);
    il.Emit(OpCodes.Ldtoken, extractor);
    var methodHandleValueProp = typeof(RuntimeMethodHandle).GetProperty(nameof(RuntimeMethodHandle.Value))!.GetGetMethod();
    il.Emit(OpCodes.Call, methodHandleValueProp);
    var funcType = typeof(Func<,>).MakeGenericType(typeBuilder, typeof(int));
    var createDelegateMethod = typeof(Delegate).GetMethod(nameof(Delegate.CreateDelegate), new[] { typeof(Type), typeof(object), typeof(IntPtr) })!;
    il.Emit(OpCodes.Call, createDelegateMethod);

    var orderFunc = typeof(Enumerable).GetMethods().Single(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
    il.Emit(OpCodes.Call, orderFunc.MakeGenericMethod(typeBuilder, typeof(int)));
    il.Emit(OpCodes.Ret);
    return typeBuilder;
}

内容的提问来源于stack exchange,提问作者Mason Wheeler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:34:55