首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Mono.Cecil:注入try/finally?

Mono.Cecil:注入try/finally?
EN

Stack Overflow用户
提问于 2012-10-07 22:31:42
回答 2查看 2.1K关注 0票数 4

很好地概述了在Mono.Cecil was answered here中实现try/catch,但他没有完成完整的try/catch/finally。那么如何使用Mono.Cecil实现try/finally呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-10-09 18:43:31

下面是如何注入一个finally。

首先,你需要修正你的返回语句。你只想要一个。

代码语言:javascript
复制
Instruction FixReturns()
{
    if (Method.ReturnType == TypeSystem.Void)
    {
        var instructions = body.Instructions;
        var lastRet = Instruction.Create(OpCodes.Ret);
        instructions.Add(lastRet);

        for (var index = 0; index < instructions.Count - 1; index++)
        {
            var instruction = instructions[index];
            if (instruction.OpCode == OpCodes.Ret)
            {
                instructions[index] = Instruction.Create(OpCodes.Leave, lastRet);
            }
        }
        return lastRet;
    }
    else
    {
        var instructions = body.Instructions;
        var returnVariable = new VariableDefinition("methodTimerReturn", Method.ReturnType);
        body.Variables.Add(returnVariable);
        var lastLd = Instruction.Create(OpCodes.Ldloc, returnVariable);
        instructions.Add(lastLd);
        instructions.Add(Instruction.Create(OpCodes.Ret));

        for (var index = 0; index < instructions.Count - 2; index++)
        {
            var instruction = instructions[index];
            if (instruction.OpCode == OpCodes.Ret)
            {
                instructions[index] = Instruction.Create(OpCodes.Leave, lastLd);
                instructions.Insert(index, Instruction.Create(OpCodes.Stloc, returnVariable));
                index++;
            }
        }
        return lastLd;
    }
}

然后找到第一条指令。如果它是实例构造函数,则需要跳过2。

代码语言:javascript
复制
Instruction FirstInstructionSkipCtor()
{
    if (Method.IsConstructor && !Method.IsStatic)
    {
        return body.Instructions.Skip(2).First();
    }
    return body.Instructions.First();
}

然后把它缝在一起

代码语言:javascript
复制
void InnerProcess()
{
    body = Method.Body;
    body.SimplifyMacros();
    ilProcessor = body.GetILProcessor();

    var returnInstruction = FixReturns();

    var firstInstruction = FirstInstructionSkipCtor();

    var beforeReturn = Instruction.Create(OpCodes.Nop);
    ilProcessor.InsertBefore(returnInstruction, beforeReturn);

    InjectIlForFinaly(returnInstruction);

    var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
        {
            TryStart = firstInstruction,
            TryEnd = beforeReturn,
            HandlerStart = beforeReturn,
            HandlerEnd = returnInstruction,
        };

    body.ExceptionHandlers.Add(handler);
    body.InitLocals = true;
    body.OptimizeMacros();
}
票数 10
EN

Stack Overflow用户

发布于 2016-04-04 06:06:22

我发现检查过的例子非常有用。然而,在更复杂的条件下,确实遇到了问题。在FixReturns()中,无论是空的还是非空的返回作用域,通过创建新指令来更改ret -> leave的方法都会孤立原始的指令。这可以留下具有作为操作数的孤儿的其他指令(例如,分支到原始ret)。结果代码最终是无效的。

我们简单地更新了现有ret指令的操作码/操作数对,而不是创建新的,一切看起来都很好。

干杯。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12769699

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档