2

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はオブジェクトではなくローカル変数 ( ) に対して実行されthisます。これは、割り当て時のスタックの状態によって異なりますが、バイトコードがまったく異なるいくつかの異なるシナリオに遭遇したため、この複雑さを処理する方法を探しています。

thisPUTFIELD がオブジェクトに属するフィールドを再割り当てしていることを確認するにはどうすればよいですか?


編集

既存のバイトコードを計測するのではなく、分析のみを実行するために ASM を使用しています。可能であれば、バイトコードを変更せずにこれを発見する方法を見つけたいと思います。

4

3 に答える 3

2

一般的には無理だと思います。検討:

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

于 2010-08-28T16:30:26.397 に答える
0

別のアプローチ (実行時):

AspectJ を使用して、クラスのフィールド セット/取得ポイントカットを設定できます。http://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.htmlおよびhttp://www.eclipse.org/aspectj/を参照してください。

ポイントカットを定義したら、thisJoinPoint 変数を使用して現在の実行場所を単純に出力するアドバイスを書きます。次に、プログラムを実行すると、フィールドが取得/設定されたすべての場所のログが記録されます。

これには、実行時またはコンパイル時の織り込みが必要であり、どちらの方法でもバイトコードを操作する必要があります。お役に立てれば...

于 2010-08-29T05:01:10.347 に答える
0

ASM を使用したことはありませんが、バイトコード操作の経験はあります。

PUTFIELD 命令の直前のスタックは次のようになります。

|...,object_ref,value

また

|...,object_ref,value1,value2(フィールドの型が double または long の場合)

最初のケースでは、PUTFIELD の前に次の命令を挿入できます。

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

命令 (1) は、object_ref と値をスタックに複製します。(2) 値を削除します。(3) 「this」参照をロードします。(4) 「this」が object_ref と等しい場合はコードを実行し、そうでない場合は何もせずに PUTFIELD にジャンプします。

2 番目のケース (long または double フィールド) では、この一連のバイトコード命令を使用できます。

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
于 2010-08-28T17:58:39.540 に答える