通过ASM为注入的字节代码添加try-catch块

时间:2014-07-22 08:06:22

标签: java java-bytecode-asm

我正在尝试使用ASM注入字节代码,我想用try-catch块包围注入的字节代码。但是,我在onMethodExit上得到了一个VerifyError:“堆栈高度不一致0!= 1”。

当删除try-catch块时,它按预期工作。任何指针都非常受欢迎。

这是我的代码快照:-----

 protected void onMethodEnter()  {    

        mv.visitInsn(Opcodes.ICONST_0);
        mv.visitVarInsn(ISTORE, okFlag);

        Label startTryBlock = new Label();
        Label endTryBlock = new Label();
        Label startCatchBlock = new Label();

        // Initialization try-catch block
        mv.visitTryCatchBlock(startTryBlock, endTryBlock, startCatchBlock, "java/lang/Exception");

        // starting try block
        mv.visitLabel(startTryBlock);

        mv.visitLdcInsn(className);
        mv.visitLdcInsn(methodName);
        mv.visitLdcInsn(description);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/sam/agent/trace/RootTracer", "allMethodBegin", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
        mv.visitVarInsn(ISTORE, okFlag);

        //ending try  block
        mv.visitLabel(endTryBlock); 
        Label endCatchBlock = new Label();
        mv.visitJumpInsn(GOTO, endCatchBlock);

        // start catch block
        mv.visitLabel(startCatchBlock);
        mv.visitVarInsn(ASTORE, isStatic);

        //ending catch block
        mv.visitLabel(endCatchBlock);
}



private void onMethodExit(int opcode)  {

        Label startTryBlock = new Label();
        Label endTryBlock = new Label();
        Label startCatchBlock = new Label();

        // Initialization try-catch block
        mv.visitTryCatchBlock(startTryBlock, endTryBlock, startCatchBlock, "java/lang/Exception");

        // starting try block
        mv.visitLabel(startTryBlock);

        if(opcode == ATHROW){
            mv.visitInsn(Opcodes.DUP);
            mv.visitLdcInsn(className);
            mv.visitLdcInsn(methodName);
            mv.visitLdcInsn(description);
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/sam/agent/trace/RootTracer", "recordException", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
        }
        mv.visitLdcInsn(className);
        mv.visitLdcInsn(methodName);
        mv.visitLdcInsn(description);
        mv.visitVarInsn(ILOAD, okFlag);
        mv.visitLdcInsn(opcode);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/sam/agent/trace/RootTracer", "MethodEnd", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)V");

        // ending try block
        mv.visitLabel(endTryBlock); 
        Label endCatchBlock = new Label();
        mv.visitJumpInsn(GOTO, endCatchBlock);

        // starting catch block
        mv.visitLabel(startCatchBlock);
        mv.visitVarInsn(ASTORE, isStatic); // FAILED Here

        // ending catch block
        mv.visitLabel(endCatchBlock);
    }

1 个答案:

答案 0 :(得分:1)

任何Java方法都在操作数堆栈上执行。在执行期间,值被推入堆栈或从堆栈弹出。当您在onMethodExit(int) - 发射方法中使用跳转指令时,您需要确保操作数堆栈上的任何目标都具有完全相同的类型的元素跳转指令。这些元素类型必须相同,独立于通过代码的路径,从该目标到达跳转指令的目标。对于您的代码,情况似乎并非如此。一个代码路径似乎到达一个跳转指令目标,其中一个元素在操作数堆栈上,另一个路径到达相同的目标语句,堆栈上有零个元素。因此投诉Inconsistent stack height 0 != 1

问题很可能与:

有关
mv.visitJumpInsn(GOTO, endCatchBlock);

我假设验证程序在到达finally块时抱怨您的异常块在堆栈上的异常引用完成。对于没有抛出异常的路径,情况并非如此。

尝试删除该行

mv.visitInsn(Opcodes.DUP);

if语句中,操作数堆栈始终包含零元素。我假设您让ASM为您计算堆栈映射帧。