代码之家  ›  专栏  ›  技术社区  ›  Grundlefleck anujkk

如何检查字节码操作PUTFIELD是否正在使用ObjectWeb ASM重新分配属于“this”对象的字段?

  •  2
  • Grundlefleck anujkk  · 技术社区  · 15 年前

    我正在使用 ASM 字节码操作框架,用于对Java代码执行静态分析。我希望检测对象的字段何时被重新分配,即何时发生此类代码:

    class MyObject {
        private int value;
        void setValue(int newValue) { this.value = newValue; }
    }
    

    ClassVisitor

    @Override
    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
        if(opcode == Opcodes.PUTFIELD) {
            // do whatever here
        }
    }
    

    但是,不管拥有字段的对象是谁,都会调用此代码。我想找到一个更具体的情况,即PUTFIELD操作在 this 对象。例如,我想区分第一个代码段和如下代码:

    public MyObject createNewObjectWithDifferentField() {
        MyObject newObject = new MyObject();
        newObject.value = 43;
        return newObject;
    }
    

    在上面的例子中,PUTFIELD操作仍然执行,但是这里它是在一个局部变量上执行的( newObject 对象。这将取决于赋值时堆栈的状态,但是我遇到了一些不同的情况,其中字节码是完全不同的,我正在寻找处理这种复杂性的方法。

    反对?


    我使用ASM只执行分析,而不是检测现有的字节码。如果可能的话,我希望找到一种不改变字节码的方法来发现这个问题。

    3 回复  |  直到 15 年前
        1
  •  2
  •   Jevgeni Kabanov    15 年前

    我认为在一般情况下这是不可能的。考虑:

    class MyObject {
      private int value;
      void mymethod1() {
        mymethod2(Math.random() > 0.5 ? this : new MyObject());
      }
    
      void mymethod2(MyObject that) {
        that.value = 1;
      }
    }
    

    在更简单的情况下,可以将堆栈跟踪回 ALOAD 0 ,在实例方法中引用 this .

        2
  •  0
  •   H-H    15 年前

    我从未使用过ASM,但是,我有字节码操作的经验。

    |...,object_ref,value
    

    |...,object_ref,value1,value2 (如果字段类型为double或long)

    1: DUP2
    2: POP
    3: ALOAD_0
    4: IF_ACMPNE X
    5: put your code here
    ...
    ...
    X: PUTFIELD
    

    指令(1)复制堆栈上的对象_ref和值。(2) 删除该值。(3) 加载“this”引用。(4) 如果'this'等于对象\u ref,则执行代码,否则不执行任何操作并跳转到PUTFIELD。

    1: DUP2_X1
    2: POP2
    3: DUP
    4: ALOAD_0
    5: IF_ACMPNE 7
    6: put your code here
    ...
    ...
    7: DUP_X2
    8: POP
    9: PUTFIELD
    
        3
  •  0
  •   Andy    15 年前

    另一种方法(运行时):

    可以使用AspectJ为类设置字段集/获取切入点。参见: http://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html http://www.eclipse.org/aspectj/

    在定义切入点之后,您将编写一些建议,通过使用thisJoinPoint变量简单地打印出当前的执行位置。然后,当运行你的程序时,你会有一个很好的日志记录所有字段被获取/设置的地方。

    推荐文章