JVM でバイトコードはどのように検証されますか?
2 に答える
オラクル自身には、ここでどのように機能するかについての小さなスニペットページがあります.
基本的に、JRE は JDK を信頼しません。これは、どの JDK コンパイラがクラス ファイルを作成したかを認識していないためです。検証されるまで、クラス ファイルを敵対的なものとして扱います。
さらに、バイトコードの検証は、Sun が「悪意のあるコンパイラ」と呼ぶものから保護するために必要な手順です。Sun 独自の Java コンパイラは、Java ソース コードが安全規則に違反していないことを保証しますが、アプリケーションがコード フラグメントをインポートするとき、コード フラグメントが Java 言語の安全規則に従っているかどうかは実際にはわかりません。つまり、コードは信頼できる Java コンパイラによって生成されたものではない可能性があります。
その場合、マシンの Java ランタイム システムはフラグメントが不良であると想定し、バイトコード検証を行う必要があります。
Java 仮想マシンは、この検証プロセスが完了するまでバイトコードを認識しません。バイトコードがロードされるときにこれを行うことには、コードが実行されるたびに多くの実行時チェックを実行する必要がないという利点もあります。正しいことが検証されているため、実行を開始すると、他の方法よりも高速に実行できます。
リンクされた図の表現は次のとおりです。
<<<=== Unsafe / Safe ===>>>
\
+---------------+ +-------------------+
| Java source | +--> | Class loader | --+
+---------------+ | | Bytecode verifier | |
| | +-------------------+ |
V | / |
+---------------+ | \ V
| Java compiler | Network / +-------------------+
+---------------+ | \ | JVM/JIT |
| | / +-------------------+
V | \ |
+---------------+ | / V
| Java bytecode | --+ \ +-------------------+
+---------------+ / | Operating system |
\ +-------------------+
/ |
\ V
/ +-------------------+
\ | Hardware |
/ +-------------------+
\
<<<=== Unsafe / Safe ===>>>
最良の情報源は、おそらく JVM 仕様の関連セクション4.10 Verification of class Filesです。
詳細についてはリンクを参照してください。
リンク時の検証により、インタープリターのパフォーマンスが向上します。解釈された各命令の実行時に制約を検証するために実行しなければならない高価なチェックをなくすことができます。Java 仮想マシンは、これらのチェックがすでに実行されていると見なすことができます。たとえば、Java 仮想マシンは次のことを既に認識しています。
- オペランド スタックのオーバーフローまたはアンダーフローはありません。
- すべてのローカル変数の使用と保存は有効です。
- すべての Java 仮想マシン命令への引数は、有効な型です。
検証者は、Code 属性のコード配列を見なくても実行できる検証も実行します (§4.7.3)。実行されるチェックには、次のものが含まれます。
- 最終クラスがサブクラス化されておらず、最終メソッドがオーバーライドされていないことを確認します (§5.4.5)。
- すべてのクラス ( を除く
Object
) に直接のスーパークラスがあることを確認しています。- 定数プールが文書化された静的制約を満たしていることを確認します。たとえば、
CONSTANT_Class_info
定数プール内の各構造体には、そのname_index
項目に構造体の有効な定数プール インデックスが含まれていますCONSTANT_Utf8_info
。- 定数プール内のすべてのフィールド参照とメソッド参照が有効な名前、有効なクラス、および有効な型記述子を持っていることを確認しています。