2

可能重复:
Mono.Cecil 是否负责分支等位置?

我正在开发一个项目,该项目要求我在我的应用程序中调用某些方法后插入一个静态方法调用。我正在使用 Mono Cecil,并且在大多数情况下一切正常。但是,当更新的程序集写入磁盘时,我遇到了一些分支偏移量被破坏的情况。这是我的代码的样子:

公共无效仪器方法(方法定义方法)
{
    var 处理器 = method.Body.GetILProcessor();

    var instr = GetStaticInstrumentMethod();
    var 仪器 = method.Module.Import(instr);
    var call = method.Body.Instructions.First(i => i.IsCallImInterestedIn());
    处理器.InsertBefore(调用,仪器);
}

因此,该代码在 90% 的情况下都可以正常工作 - 目标方法通过我的额外调用进行了检测,并且一切正常。

另外 10% 的情况下,检测方法无法执行,并且尝试在 ILSpy 中查看它时出错。ILSpy 错误是:

ICSharpCode.Decompiler.DecompilerException:错误反编译 System.Object Savo.Utilities.Mapping.ReflectionMapper::MapTo(System.Object,System.Object)
 ---> System.NullReferenceException:对象引用未设置为对象的实例。
   在 ICSharpCode.Decompiler.ILAst.ILAstBuilder.c__DisplayClass33.b__26(ByteCode b)
   在 System.Linq.Enumerable.Any[TSource](IEnumerable`1 源,Func`2 谓词)
   在 ICSharpCode.Decompiler.ILAst.ILAstBuilder.ConvertLocalVariables(List`1 body)
   在 ICSharpCode.Decompiler.ILAst.ILAstBuilder.StackAnalysis(MethodDefinition methodDef)
   在 ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(IEnumerable`1 参数)
   在 ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition methodDef,DecompilerContext 上下文,IEnumerable`1 参数)
   --- 内部异常堆栈跟踪结束 ---
   在 ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition methodDef,DecompilerContext 上下文,IEnumerable`1 参数)
   在 ICSharpCode.Decompiler.Ast.AstBuilder.CreateMethod(MethodDefinition methodDef)
   在 ICSharpCode.ILSpy.CSharpLanguage.DecompileMethod(MethodDefinition 方法,ITextOutput 输出,DecompilationOptions 选项)
   在 ICSharpCode.ILSpy.TextView.DecompilerTextView.DecompileNodes(反编译上下文上下文,ITextOutput textOutput)
   在 ICSharpCode.ILSpy.TextView.DecompilerTextView.c__DisplayClass10.b__f()

我已经用 ildasm 反编译了代码,我注意到在保存程序集时如何更新偏移似乎存在问题。我没有对调用的偏移量做任何事情(试图手动设置它们,但看到了同样的问题)。我的一种问题方法的仪器前反汇编如下所示:

IL_000e:  br.s       IL_005e
IL_0010:  ldloca.s   CS$5$0000
IL_0012:  call       instance !0 valuetype         [mscorlib]System.Collections.Generic.List`1/Enumerator<class MyThing>::get_Current()
IL_0017:  stloc.0
IL_0018:  nop

... business logic ...    

IL_005d:  nop
IL_005e:  ldloca.s   CS$5$0000
IL_0060:  call       instance bool valuetype      [mscorlib]System.Collections.Generic.List`1/Enumerator<class MyThing>::MoveNext()
IL_0065:  stloc.3
IL_0066:  ldloc.3
IL_0067:  brtrue.s   IL_0010
IL_0069:  leave.s    IL_007a

当我查看已检测的反汇编时,此示例中对应于 IL_0067 的行显示为:

IL_00bc:    brtrue.s    IL_0129

由于当前方法中不存在 IL_0129,因此无法编译。

我注意到了,但我还没有证明这只发生在迭代器周围。到目前为止发生这种情况的两种情况的 C# 代码都是 foreach 循环,并且不正确的分支目标似乎都与 foreach 循环的结束条件有关。

所以,我的问题是:我需要手动管理偏移量引用,还是我做错了什么?

4

0 回答 0