プログラムの正しさを保証するためにバイトコードベリファイアが実行しなければならない主要なタスクを誰かリストアップできますか? JVM 仕様で定義された標準的な最小限の責任はありますか? また、検証がロードや初期化などの他のフェーズにまたがっているかどうかも疑問に思っていました。
3 に答える
これは、JVM 仕様の第 4.10 章で指定されています。クラス Files の検証。
このページの大部分は、タイプ セーフのさまざまな側面について説明しています。プログラムがタイプ セーフであることを確認するために、ベリファイアは、各プログラム ポイントでオペランド スタックに存在するオペランドのタイプを特定し、それらがそれぞれの命令で期待されるタイプと一致することを確認する必要があります。
それが検証するその他の事項には、以下が含まれますが、これらに限定されません。
分岐は、メソッドのコード配列の境界内にある必要があります。
すべての制御フロー命令のターゲットは、それぞれ命令の開始です。ワイド命令の場合、ワイド オペコードは命令の開始と見なされ、そのワイド命令によって変更された操作を与えるオペコードは、命令の開始とは見なされません。命令の途中への分岐は許可されていません。
命令は、そのメソッドが割り当てることを示すローカル変数の数以上のインデックスにあるローカル変数にアクセスしたり、変更したりすることはできません。
定数プールへのすべての参照は、適切なタイプのエントリである必要があります。(たとえば、命令 getfield はフィールドを参照する必要があります。)
コードは命令の途中で終了しません。
実行がコードの最後から外れることはありません。
例外ハンドラごとに、ハンドラによって保護されるコードの開始点と終了点は、命令の先頭にある必要があります。終了点の場合は、コードの末尾の直後にある必要があります。始点は終点より前でなければなりません。例外ハンドラ コードは、有効な命令で開始する必要があり、ワイド命令によって変更されるオペコードで開始してはなりません。
最後のステップとして、ベリファイアはデータフロー分析も実行します。これにより、初期化されていないローカル変数を参照する命令がないことが確認されます。
または、James Gosling によるJava 言語環境のホワイト ペーパーを参照してください。
バイトコード検証ツールは、バイトコードをトラバースし、型状態情報を構築し、すべてのバイトコード命令に対するパラメーターの型を検証します。
この図は、Java 言語ソース コードから Java コンパイラを経由して、クラス ローダーとバイトコード ベリファイアを経由し、インタープリタとランタイム システムを含む Java 仮想マシンに至るまでのデータと制御の流れを示しています。重要な問題は、Java クラス ローダーとバイトコード ベリファイアが、バイトコード ストリームの主要なソースについて仮定を行わないことです。コードはローカル システムから取得されたものであるか、地球の半周を移動した可能性があります。バイトコード ベリファイアは、一種のゲートキーパーとして機能します。Java インタープリターに渡されたコードが実行に適した状態にあり、Java インタープリターが壊れることを恐れずに実行できることを保証します。インポートされたコードは、検証者のテストに合格するまで、決して実行できません。検証が終わったら、
- オペランド スタックのオーバーフローまたはアンダーフローがない
- すべてのバイトコード命令のパラメータの型は、常に正しいことが知られています
- オブジェクト フィールドへのアクセスは、プライベート、パブリック、または保護された合法的であることが知られています。
このすべてのチェックは耐え難いほど詳細に見えますが、バイトコード検証ツールが作業を完了するまでに、Java インタープリターは、コードが安全に実行されることを認識して続行できます。これらのプロパティを知っていると、Java インタープリターは何もチェックする必要がないため、はるかに高速になります。オペランド型チェックもスタック オーバーフロー チェックもありません。したがって、通訳者は、信頼性を損なうことなくフルスピードで機能することができます。
次のことを行います。
- オペランド スタックのオーバーフローまたはアンダーフローがない
- すべてのバイトコード命令のパラメータの型は、常に正しいことが知られています
- オブジェクト フィールドへのアクセスは、プライベート、パブリック、または保護された合法的であることが知られています。
参照: http://java.sun.com/docs/white/langenv/Security.doc3.html