assembly 如何使用Java中的ASM库来检测if-else块?

pqwbnv8z  于 2022-12-19  发布在  Java
关注(0)|答案(1)|浏览(173)

我一直在尝试使用java中的ASM库来插装分支相关的代码,假设这是我想插装的一段代码:

if (true) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }

下面是我的代码:

//put true on stack
            mv.visitInsn(Opcodes.ICONST_1);
  
            //create labels
            Label elseLabel = new Label();
            Label endLabel = new Label();
            mv.visitJumpInsn(Opcodes.IFEQ, elseLabel);

            // instrument code for the "if" block
            mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("true");
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

            mv.visitJumpInsn(Opcodes.GOTO, endLabel);
            mv.visitLabel(elseLabel);

            //instrument code for else block
            mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("false");
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

            mv.visitLabel(endLabel);

可以使用Intellij自己的反编译器正确地显示和解释插入的字节码。
但是,代码无法运行,存在VerifyError x1c 0d1x
而这是运行“javap -c”命令生成的可读字节码。

public void doSomething1();
    Code:
       0: aload_0
       1: invokevirtual #5                  // Method doSomething:()V
       4: iconst_1
       5: invokestatic  #6                  // Method org/junit/jupiter/api/Assertions.assertTrue:(Z)V
       8: iconst_1
       9: ifeq          23
      12: getstatic     #44                 // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #46                 // String true
      17: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: goto          31
      23: getstatic     #44                 // Field java/lang/System.out:Ljava/io/PrintStream;
      26: ldc           #48                 // String false
      28: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      31: return
}

你能帮我一下吗?谢谢!

7gyucuyw

7gyucuyw1#

添加字节码是没有错误的。但是,只需传递ClassWriter.COMPUTE_FRAME而不是ClassWriter.ComputeMax就可以解决这个问题。(感谢JohannesKuhn和任何帮助过我的人)。红色标记的VerifyError表明了这一点(尽管我不知道)。
COMPUTE_MAX似乎适用于java5或更早版本。

相关问题