7

私が取り組んでいるレガシー プロジェクトには、一連のバイナリ jar ファイルの形式でいくつかの外部ライブラリが含まれています。分析と潜在的なパッチ適用のために、このライブラリのソースを受け取り、それらを使用して新しいバイナリを構築し、詳細で十分な長さの回帰テストを行った後、これらのバイナリに切り替えることにしました。

すでにソースを取得してビルドしていると仮定します (実際には計画段階です)。実際のテストの前に、いくつかの「互換性チェック」を実行して、ソースが「古い」バイナリとは劇的に異なるものを表している可能性を排除したいと思います。

このjavapツールを使用して、コンパイルに使用された JDK のバージョンを抽出できました (少なくとも JDK のバージョンであると思います)。それによると、バイナリはメジャー バージョン 46 とマイナー 0 を使用してビルドされました。この記事によると、JDK 1.2 にマップされます。

ソースのコンパイルに同じ JDK が使用されると仮定します。

問題は、これらのバイナリが両方とも同じソースから構築されている場合、信頼できる効果的な検証方法があるかどうかです。すべてのメソッド シグネチャとクラス定義が同一であるかどうか、およびほとんどまたはすべてのメソッド実装が同一/類似しているかどうかを知りたいです。

ライブラリはかなり大きいので、逆コンパイルされたバイナリの詳細な分析はオプションではない可能性があると思います。

4

4 に答える 4

1

多段階のプロセスを提案します。

以前に提案されたJardiffまたは同様のものを適用して、APIに違いがあるかどうかを確認します。可能であれば、プライベートメソッドなどをレポートするオプションを備えたツールを選択してください。実際には、パブリックAPIが変更されていない場合でも、Javaでの大幅な実装変更により、一部のメソッドとクラスが変更される可能性があります。

APIが一致する場合は、ランダムに選択されたいくつかのファイルを指定されたコンパイラでコンパイルし、結果と元のクラスファイルを逆コンパイルして、結果を比較します。それらが一致する場合は、不一致が見つかるか、すべてをチェックするまで、同じプロセスをますます大きなコード本体に適用します。

逆コンパイルされたコードの差分は、実際のクラスファイルよりも、違いの性質についての手がかりを与える可能性が高く、重要でない違いをフィルタリングするのが簡単です。

不一致が発生した場合は、それを分析します。気にしないことが原因かもしれません。その場合は、その形式の違いを削除し、コンパイルと比較のプロセスを再開するスクリプトを作成してみてください。広範囲にわたる不一致が発生した場合は、最適化などのコンパイラーパラメーターを試してください。コンパイラー・パラメーターを調整して差異が解消された場合は、一括比較を続行してください。このフェーズの目的は、サンプルファイルで一致を生成するコンパイラーパラメーターと逆コンパイルされたコードフィルターの組み合わせを見つけ、それらをライブラリーの一括比較に適用することです。

逆コンパイルされたコードで適度に近い一致を取得できない場合は、適切なソースコードがない可能性があります。それでも、APIが一致する場合は、システムを構築し、コンパイルの結果を使用してテストを実行する価値があるかもしれません。テストが少なくともソースからビルドしたバージョンでも実行される場合は、それを使用して作業を続行します。

于 2012-11-12T15:30:19.273 に答える
0

さまざまな JAR 比較ツールがあります。以前はかなり良かったのはJardiffです。しばらく使っていませんが、まだ使えると思います。同じスペースに、ニーズに合った商用製品もいくつかあります。

于 2012-11-12T15:14:38.570 に答える
0

メソッド シグネチャには、jardiff などのツールを使用します。

実装の類似性については、大まかな推測に戻る必要があります。オペコード レベルでのバイトコードの比較は、コンパイラに依存し、多数の偽陰性につながる可能性があります。この場合、フォールバックして、LineNumberTableを使用してクラスのメソッドを比較できます。

各メソッドの行番号のリストが表示されます (クラス ファイルがデバッグ フラグを使用してコンパイルされている場合に限ります。これは、非常に古いライブラリや商用ライブラリでは欠落していることがよくあります)。

2 つのクラス ファイルが同じソース コードからコンパイルされる場合、少なくとも各メソッドの行番号は正確に一致する必要があります。

LineNumberTable を取得するには、Apache BCEL などのライブラリを使用できます。

  // import org.apache.bcel.classfile.ClassParser;
  JavaClass fooClazz = new ClassParser( "Foo.class" ).parse();
  for( Method m : fooClazz.getMethods() )
  {
     LineNumberTable lnt = m.getLineNumberTable();
     LineNumber[] tab = lnt.getLineNumberTable();
     for( LineNumber ln : tab )
     {
        System.out.println( ln.getLineNumber() );
     }
  }
于 2012-11-12T16:52:03.123 に答える
0

Perception が言及した Jardiff は良いスタートですが、理論的に 100% 確実に実行する方法はありません。これは、同じソースを異なるコンパイラ、異なるコンパイラ構成および最適化レベルでコンパイルできるためです。そのため、クラスとメソッドのシグネチャを超えてバイナリ コード (バイトコード) を比較する方法はありません。

メソッドの「同様の実装」とはどういう意味ですか? 巧妙なコンパイラがelseケースを削除したとしましょう。条件が真ではない可能性があることがわかったからです。2つは似ていますか?はいといいえ.. :-)

私見の最善の方法は、ライブラリのすべての重要な機能をチェックする非常に優れた回帰テスト ケースを設定することです。これは恐ろしいことかもしれませんが、長期的にはバグを探すよりも安上がりかもしれません。それはすべて、このプロジェクトでのあなたの将来の計画にかかっています。ささいな簡単な決定ではありません。

于 2012-11-12T15:24:01.247 に答える