我想检测一个类的方法之一是否使用ASM改变了某个实例字段。例如:

public class Box {
    public Object o;

    public void mutate() {
        o = new Object();
    }
}


问题:实例字段是否被Box类的方法之一改变了?在这种情况下,可以。

使用ASM树库中的MethodNode类,我可以获取如下所示方法的操作码

-1 -1 25 187 89 183 181 -1 -1 177 -1


该数组包含用于putfield的操作码181,但是如何确定是分配给Box.o的字段呢?

顺便说一句:为什么数组包含-1值?

特纳克斯

最佳答案

不知道为什么要查看原始字节码。我会看个别说明。

public class Box {
    public Object o;

    public void mutate() {
        o = new Object();
    }

    public static void main(String... args) throws IOException {
        ClassReader cr = new ClassReader(Box.class.getName());
        ASMifierClassVisitor acv = new ASMifierClassVisitor(new PrintWriter(System.out));
        cr.accept(acv, 0);
    }
}


版画

... lots of code ...
{
mv = cw.visitMethod(ACC_PUBLIC, "mutate", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(11, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitTypeInsn(NEW, "java/lang/Object");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitFieldInsn(PUTFIELD, "Box", "o", "Ljava/lang/Object;");
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(12, l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLocalVariable("this", "LBox;", null, l0, l2, 0);
mv.visitMaxs(3, 1);
mv.visitEnd();
}
... more code ...


您可以看到方法访问者的调用方式为

mv.visitFieldInsn(PUTFIELD, "Box", "o", "Ljava/lang/Object;");


这应该告诉您您想知道什么。



如果您有构造函数(建议您这样做)

private Object o;

public Box(Object o) {
    this.o = o;
}


您可能要区别对待此“突变”,因为它在构造函数中。

10-05 23:40