0

ASM を使用してメソッドを try/finally ブロックにラップしようとしています。具体的には、「3.2.3 メソッドの終了前にコードを挿入する」の「ASM フレームワークを使用して一般的なバイトコード変換パターンを実装する」org.objectweb.asm.commons.AdviceAdapterで説明されている手法を拡張し、従っています。

また、LocalVariablesSorter(のスーパークラスAdviceAdapter)を使用して、finally ブロックで使用するメソッドの開始時にローカル変数を追加しています。

ASM で変更しようとしているメソッドがあります。このメソッドは 3 つの引数を取り、独自のローカルはありません。

class Example {
    public static int f4(int i, long l, int f) {
        return (int) (i + l + f);
    }
}

私のfinallyブロックは例外ハンドラのターゲットである可能性があるため、呼び出し so を追加してsuper.visitFrame(F_NEW, ...)、メソッド パラメータを渡します。これはスーパークラスを呼び出すため、 newLocal が によってこのフレームに追加されることを期待していLocalVariablesSorterます。しかし、これを ASM パイプラインで実行すると、Java 7 でエラーが発生しますjava.lang.VerifyError: Bad local variable type in method Example.f4(IJI)I at offset 32

メソッドののソースをLocalVariablesSorter見るvisitFrameと、ブール値がchangedあり、変更されていない場合visitFrame、作成される可能性のある新しいローカルの考慮がスキップされることがわかります。このchangedブール値は、アップストリームのバイトコードが変数に対して特定の操作を実行する場合にのみ設定されるように見えますが、LocalVariablesSorter新しいローカルを作成するために使用するために再マップする必要がありました (f4()上記の方法ではそのような操作は発生しません)。

この回避策を適用すると:

       Field field = LocalVariablesSorter.class.getDeclaredField("changed");
       field.setAccessible(true);
       field.setBoolean(this, true);

Java 7 のベリファイアを通過できます。また、TraceClassVisitorASM ユーティリティを使用すると、finally ブロックの開始直前のスタック マップ フレームに違いが見られます。

前:

FRAME FULL [I J I] [java/lang/Throwable]

リフレクション ハックの後 (追加する新しいローカルは int です):

FRAME FULL [I J I I] [java/lang/Throwable]

周囲のコードを共有していないことはわかっていますが、私の質問はより一般的です。このchangedブール値は による誤った最適化LocalVariablesSorterですか? それとも、どういうわけかそれを悪用しているのですか?

4

1 に答える 1

0

呼び出しはローカルを追加しません。LocalVariablesSorter.visitFrame(..)追加のフレームに関する情報を記録するように ASM に通知するだけです。を呼び出して、ローカルを追加する必要がありますLocalVariablesSorter.newLocal(..)

一般的に、ASM でバグを発見したと思われる場合は、バグ レポートをASM イシュー トラッカーに送信し、問題を再現できるテスト コード (テスト クラスと完全な変換など) を提供することをお勧めします。

于 2013-01-24T20:46:55.200 に答える