IL代码操作可能会使运行时不稳定

时间:2013-11-27 20:58:16

标签: c# .net-4.0 il

当我运行它时,我当前有以下代码我得到错误代码操作可能会破坏运行时的稳定性(这个我更新的il代码匹配sigil它仍然无法工作)

public static Func<IDataReader, Object> TestMethod<T>()
    {
        var method = new DynamicMethod("", typeof(Object), new[]
        {
            typeof ( IDataReader )
        });
        var il = method.GetILGenerator();
        Label whileIf = il.DefineLabel();
        Label whileStart = il.DefineLabel();
        Label methodEnd = il.DefineLabel();
        il.Emit(OpCodes.Newobj, typeof(List<string>).GetConstructor(new Type[0]));
        il.Emit(OpCodes.Stloc_0);
        il.Emit(OpCodes.Br_S, whileIf);
        il.MarkLabel(whileStart);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Callvirt, typeof(IDataRecord).GetMethod("GetString"));
        il.Emit(OpCodes.Callvirt, typeof(List<string>).GetMethod("Add"));
        il.MarkLabel(whileIf);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Callvirt, typeof(IDataReader).GetMethod("Read"));
        il.Emit(OpCodes.Brtrue_S, whileStart);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ret);

        return (Func<IDataReader, Object>)method.CreateDelegate(typeof(Func<IDataReader, Object>));
    }

它是根据以下代码创建的:

public List<string> method(IDataReader dataReader)
    {
        var result = new List<string>();
        while (dataReader.Read())
            result.Add(dataReader.GetString(0));
        return result;
    }

其中生成以下IL代码:

IL_0000:  nop         
IL_0001:  newobj      System.Collections.Generic.List<System.String>..ctor
IL_0006:  stloc.0     // result
IL_0007:  br.s        IL_0017
IL_0009:  ldloc.0     // result
IL_000A:  ldarg.1     
IL_000B:  ldc.i4.0    
IL_000C:  callvirt    System.Data.IDataRecord.GetString
IL_0011:  callvirt    System.Collections.Generic.List<System.String>.Add
IL_0016:  nop         
IL_0017:  ldarg.1     
IL_0018:  callvirt    System.Data.IDataReader.Read
IL_001D:  stloc.2     // CS$4$0001
IL_001E:  ldloc.2     // CS$4$0001
IL_001F:  brtrue.s    IL_0009
IL_0021:  ldloc.0     // result
IL_0022:  stloc.1     // CS$1$0000
IL_0023:  br.s        IL_0025
IL_0025:  ldloc.1     // CS$1$0000
IL_0026:  ret  

我正在IL中编写此代码,因为我最终会扩展代码,动态创建此代码以从TArg填充类型。对不起,我没有更多关于视觉工作室给我的信息。

这是我的sigil代码,它可以正常运行和运行:

var emiter = Emit<Func<IDataReader, List<String>>>.NewDynamicMethod("MyMethod");

            var whileIf = emiter.DefineLabel("whileIf");
            var whileStart = emiter.DefineLabel("whileStart");

            emiter.DeclareLocal(typeof(List<string>), "0");

            emiter.NewObject<List<String>>();
            emiter.StoreLocal("0");
            emiter.Branch(whileIf);
            emiter.MarkLabel(whileStart);
            emiter.LoadLocal("0");
            emiter.LoadArgument(0);
            emiter.LoadConstant(0);
            emiter.CallVirtual(typeof(IDataRecord).GetMethod("GetString"));
            emiter.CallVirtual(typeof(List<string>).GetMethod("Add"));
            emiter.MarkLabel(whileIf);
            emiter.LoadArgument(0);
            emiter.CallVirtual(typeof(IDataReader).GetMethod("Read"));
            emiter.BranchIfTrue(whileStart);
            emiter.LoadLocal("0");
            emiter.Return();
            Func<IDataReader, List<string>> result = emiter.CreateDelegate();

            Disassembler<Func<IDataReader, List<string>>>.Disassemble( result );

            return result;

2 个答案:

答案 0 :(得分:2)

这通常意味着堆栈不平衡或错误的调用(静态与虚拟)。我不是在电脑上检查堆栈状态,但是:如果你不确定,我强烈建议使用像“sigil”这样的工具。它是明确设计的,一旦你在发出错误时告诉你,而不是在你以后运行它时。一旦你完成它就会告诉你这个问题。

但这些绝对是错误的方式:

    il.Emit( OpCodes.Ldarg_0 );
    il.MarkLabel( whileIf );

第一次通过它直接分支到whileIf,你在空堆栈上进行调用。

答案 1 :(得分:0)

当我编写更多IL时,我编写了这些帮助方法,让我创建委托,同时生成调试程序集。使用组件对于运行反射器工具以及PEVerify非常有用。 https://bitbucket.org/mburbea/delegatedproxy/src/483a0120ff845379898ffad790082c62e43efb4e/Utilities/CodeGen.cs?at=master

这是我的实现,我基本上从未在我的各个项目之间进行更改。