【问题标题】:Detecting field mutation using ASM使用 ASM 检测字段突变
【发布时间】:2012-03-09 12:51:50
【问题描述】:

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

public class Box {
    public Object o;

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

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

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

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

这个数组包含 putfield 的操作码 181,但我怎么知道它是分配的字段 Box.o?

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

Tnx

【问题讨论】:

标签: java field variable-assignment java-bytecode-asm


【解决方案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 ...

可以看到方法visitor被调用了

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

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


如果你有一个构造函数(我建议你这样做)

private Object o;

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

您可能希望以不同的方式对待这种“突变”,因为它在构造函数中。

【讨论】:

  • ASMifierClassVisitor 是标准的 ASM 类吗?我添加了asm-util-4.0.jar,但还是无法导入org.objectweb.asm.util.ASMifierClassVisitor。
  • 我添加了 asm-all 版本 3.3.1。你不需要这个类,只是看看你会得到什么事件。在您的情况下,您实际上并不需要它来解决您的问题。
  • Okee,tnx。但我不确定现在该怎么做。你的意思是我必须实现我自己的 classvisitor 和 methodVisitor 子类来检查是否分配了一个字段?
  • 这就是我会做的。当使用visitFieldInsn() 调用方法时,您可以让它检查指令是否为 PUTFIELD。
  • Okee,但我不确定我是如何让我的自定义 classVisitor(论证接受 ClassReader)使用我的 methodVisitor。你有这样的例子吗?抱歉,我是 ASM 和 java 字节码的新手。
【解决方案2】:

还找到了另一种使用tree API的解决方案,更适合我的应用:

private boolean methodMutatesField(List<MethodNode> methods, FieldNode field, ClassNode fieldOwner) {

    for(MethodNode methodNode : methods) {
        Iterator<AbstractInsnNode> instructionIterator = methodNode.instructions.iterator();

        while (instructionIterator.hasNext()) {
            AbstractInsnNode abstractInsNode = instructionIterator.next();

            if(abstractInsNode.getType() != AbstractInsnNode.FIELD_INSN) {  
                continue;
            } 

            FieldInsnNode fieldInsnNode = (FieldInsnNode) abstractInsNode;

            if(fieldInsnNode.getOpcode() != Opcodes.PUTFIELD) {
                continue;
            }

            if(fieldInsnNode.name.equals(field.name) && fieldInsnNode.owner.equals(fieldOwner.name)) {
                return true;
            }
        }
    }

    return false;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    相关资源
    最近更新 更多