制約

.dex は、Dalvik バイトコード用のトランスポート形式のファイルです。有効な .dex ファイルであることを保証する構文上の制約と意味論的な制約が存在し、有効な .dex ファイルのみをサポートするランタイムが必要とされます。

一般的な .dex 整合性制約

一般的な整合性制約は、.dex ファイルの大まかな構造に関係します。詳しくは .dex 形式をご覧ください。

ID 説明
G1 .dex ファイルの magic ナンバーは dex\n035\0 または dex\n037\0 でなければなりません。
G2 チェックサムは、ファイル コンテンツ全体の Adler-32 チェックサムでなければなりません(magic フィールドと checksum フィールドを除く)。
G3 署名は、ファイル コンテンツ全体の SHA-1 ハッシュでなければなりません(magicchecksumsignature を除く)。
G4 file_size は、実際のファイルサイズ(バイト単位)と一致する必要があります。
G5 header_size は、値 0x70 を持つ必要があります。
G6 endian_tag は、ENDIAN_CONSTANT または REVERSE_ENDIAN_CONSTANT のいずれかの値を持つ必要があります。
G7 linkstring_idstype_idsproto_idsfield_idsmethod_idsclass_defsdata の各セクションで、offset フィールドと size フィールドは、両方ともゼロまたは両方ともゼロ以外でなければなりません。後者の場合、オフセットは 4 バイトで揃える必要があります。
G8 ヘッダー内のすべてのオフセット フィールド(map_off を除く)は、4 バイトで揃える必要があります。
G9 map_off フィールドは、ゼロであるか、データ セクションを指す必要があります。後者の場合、data セクションが存在しなければなりません。
G10 linkstring_idstype_idsproto_idsfield_idsmethod_idsclass_defsdata の各セクションは、互いに重複してはならず、また、ヘッダーと重複してはなりません。
G11 マップが存在する場合、各マップエントリには有効な型が必要です。それぞれの型は最大 1 回指定できます。
G12 マップが存在する場合、各マップエントリにはゼロ以外のオフセットとサイズが必要です。オフセットは、ファイルの対応するセクションを指す必要があります(たとえば、string_id_itemstring_ids セクションを指す必要があります)。また、アイテムの明示的または暗黙的なサイズは、セクションの実際の内容およびサイズと一致する必要があります。
G13 マップが存在する場合、マップエントリ n+1 のオフセットは、マップエントリ n plus than size of map entry n のオフセット以上の値でなければなりません。これは、エントリが重複しないことと、エントリの順序が「低いものから高いもの」順であることを暗黙的に意味します。
G14 string_id_itemtype_id_itemproto_id_itemfield_id_itemmethod_id_itemclass_def_itemtype_listcode_itemannotations_directory_item の型のエントリには、4 バイトで揃えたオフセットが必要です。
G15 個々の string_id_item について、string_data_off フィールドは data セクションへの有効な参照を含む必要があります。参照される string_data_item について、data フィールドは有効な MUTF-8 文字列を含む必要があり、utf16_size は文字列のデコードされた長さと一致する必要があります。
G16 個々の type_id_item について、descriptor_idx フィールドは string_ids リストへの有効な参照を含む必要があります。参照される文字列は有効な型記述子でなければなりません。
G17 個々の proto_id_item について、shorty_idx フィールドは string_ids リストへの有効な参照を含む必要があります。参照される文字列は有効な短い記述子でなければなりません。また、return_type_idx フィールドは type_ids セクションに対する有効なインデックスでなければならず、parameters_off フィールドはゼロであるか、data セクションを指す有効なオフセットでなければなりません。ゼロ以外の場合、パラメータ リストに void エントリを含めることはできません。
G18 個々の field_id_item について、class_idx フィールドと type_idx フィールドは type_ids リストに対する有効なインデックスでなければなりません。class_idx によって参照されるエントリは配列以外の参照型であることが必要です。さらに、name_idx フィールドは string_ids セクションへの有効な参照でなければならず、参照されるエントリの内容は MemberName 仕様に従う必要があります。
G19 個々の method_id_item について、class_idx フィールドは type_ids セクションへの有効なインデックスでなければならず、参照されるエントリは配列以外の参照型でなければなりません。proto_id フィールドは proto_ids リストへの有効な参照であることが必要です。name_idx フィールドは string_ids セクションへの有効な参照でなければならず、参照されるエントリの内容は MemberName 仕様に従う必要があります。
G20 個々の field_id_item について、class_idx フィールドは type_ids リストに対する有効なインデックスでなければなりません。参照されるエントリは配列以外の参照型であることが必要です。

静的なバイトコード制約

静的な制約は、バイトコードの個々の要素に対する制約です。通常は、制御分析またはデータフロー分析の手法を使用しなくてもチェックできます。

ID 説明
A1 insns 配列を空にすることはできません。
A2 insns 配列内の最初のオペコードはインデックス 0(ゼロ)を持つ必要があります。
A3 insns 配列は、有効な Dalvik オペコードのみを含む必要があります。
A4 命令 n+1 のインデックスは、可能なオペランドを考慮して、命令 n のインデックスに命令 n の長さを加えた値でなければなりません。
A5 insns 配列内の最後の命令は、インデックス insns_size-1 で終了する必要があります。
A6 すべての goto ターゲットと if-<kind> ターゲットは、同じメソッド内のオペコードでなければなりません。
A7 packed-switch 命令のすべてのターゲットは、同じメソッド内のオペコードでなければなりません。ターゲットのサイズとリストは一貫している必要があります。
A8 sparse-switch 命令のすべてのターゲットは、同じメソッド内のオペコードでなければなりません。対応する表は、一貫性を持ち、「低いものから高いもの」順に並んでいることが必要です。
A9 const-string 命令と const-string/jumbo 命令の B オペランドは、文字列定数プールに対する有効なインデックスでなければなりません。
A10 iget<kind> 命令と iput<kind> 命令の C オペランドは、フィールド定数プールに対する有効なインデックスでなければなりません。参照されるエントリはインスタンス フィールドを表す必要があります。
A11 sget<kind> 命令と sput<kind> 命令の C オペランドは、フィールド定数プールに対する有効なインデックスでなければなりません。参照されるエントリは静的フィールドを表す必要があります。
A12 invoke-virtual 命令、invoke-super 命令、invoke-direct 命令、invoke-static 命令の C オペランドは、メソッド定数プールに対する有効なインデックスでなければなりません。
A13 invoke-virtual/range 命令、invoke-super/range 命令、invoke-direct/range 命令、invoke-static/range 命令の B オペランドは、メソッド定数プールに対する有効なインデックスでなければなりません。
A14 名前が「<」で始まるメソッドは、.dex ファイルに由来するコードではなく、VM によってのみ暗黙的に呼び出される必要があります。唯一の例外は、invoke-direct による呼び出しが可能なインスタンス初期化子です。
A15 invoke-interface 命令の C オペランドは、メソッド定数プールに対する有効なインデックスでなければなりません。参照される method_id は、(クラスではなく)インターフェースに属している必要があります。
A16 invoke-interface/range 命令の B オペランドは、メソッド定数プールに対する有効なインデックスでなければなりません。参照される method_id は、(クラスではなく)インターフェースに属している必要があります。
A17 const-class 命令、check-cast 命令、new-instance 命令、filled-new-array/range 命令の B オペランドは、型定数プールに対する有効なインデックスでなければなりません。
A18 instance-of 命令、new-array 命令、filled-new-array 命令の C オペランドは、型定数プールに対する有効なインデックスでなければなりません。
A19 new-array 命令によって作成される配列のディメンションは、256 より小さくなければなりません。
A20 new 命令で、配列クラス、インターフェース、抽象クラスを参照することはできません。
A21 new-array 命令によって参照される型は、有効で、かつ非参照型でなければなりません。
A22 命令によってシングル幅の(ペアでない)形式で参照されるすべてのレジスタは、現在のメソッドに対して有効でなければなりません。つまり、レジスタのインデックスが負数でなく、registers_size より小さい値であることが必要です。
A23 命令によってダブル幅(ペア)の形式で参照されるすべてのレジスタは、現在のメソッドに対して有効でなければなりません。つまり、レジスタのインデックスが負数でなく、registers_size-1 より小さい値であることが必要です。
A24 invoke-virtual 命令と invoke-direct 命令の method_id オペランドは、(インターフェースではなく)クラスに属している必要があります。バージョン 037 より前の Dex ファイルでは、invoke-super 命令と invoke-static 命令に同じ制約が適用されます。
A25 invoke-virtual/range 命令と invoke-direct/range 命令の method_id オペランドは、(インターフェースではなく)クラスに属している必要があります。バージョン 037 より前の Dex ファイルでは、invoke-super/range 命令と invoke-static/range 命令に同じ制約が適用されます。

構造的なバイトコード制約

構造的な制約は、バイトコードの複数の要素間の関係に対する制約です。通常は、制御分析またはデータフロー分析の手法を使用しないとチェックできません。

ID 説明
B1 引数(レジスタとイミディエイト値)の数と型は、常に命令と一致する必要があります。
B2 レジスタペアを切り離すことはできません。
B3 レジスタ(またはペア)は、読み取り可能になる前に最初に割り当てる必要があります。
B4 invoke-direct 命令がインスタンス初期化子またはメソッドを呼び出す場所は、現在のクラスまたはそのスーパークラスの 1 つでなければなりません。
B5 インスタンス初期化子は、初期化されていないインスタンスでのみ呼び出される必要があります。
B6 インスタンス メソッドは初期化済みのインスタンスでのみ呼び出すことができ、インスタンス フィールドは初期化済みのインスタンスでのみアクセスできます。
B7 new-instance 命令の結果を保持するレジスタは、同じ new-instance 命令がインスタンスの初期化前に再度実行される場合、使用できません。
B8 インスタンス初期化子は、インスタンス メンバーがアクセス可能になる前に、別のインスタンス初期化子(同じクラスまたはスーパークラス)を呼び出す必要があります。ただし、継承されないインスタンス フィールドは例外で、別の初期化子と Object クラス全般を呼び出す前に割り当てることができます。
B9 すべての実際のメソッド引数は、それぞれの仮引数との代入互換性を持つ必要があります。
B10 個々のインスタンス メソッド呼び出しについて、実際のインスタンスは、命令で指定されたクラスまたはインターフェースとの代入互換性を持つ必要があります。
B11 return<kind> 命令は、そのメソッドの戻り値の型と一致する必要があります。
B12 スーパークラスの保護されたメンバーにアクセスする場合、アクセスされるインスタンスの実際の型は、現在のクラスまたはそのサブクラスの 1 つでなければなりません。
B13 静的フィールドに格納される値の型は、フィールドの型と代入互換性があるか、フィールドの型に変換可能でなければなりません。
B14 フィールドに格納される値の型は、フィールドの型と代入互換性があるか、フィールドの型に変換可能でなければなりません。
B15 配列に格納されるすべての値の型は、配列のコンポーネント型との代入互換性を持つ必要があります。
B16 throw 命令の A オペランドは、java.lang.Throwable との代入互換性を持つ必要があります。
B17 メソッドの最後のアクセス可能な命令は、後方への goto またはブランチ、returnthrow 命令のいずれかであることが必要です。insns 配列を一番下に残すことはできません。
B18 前のレジスタペアの未割り当ての片割れは、他の命令によって再割り当てされるまで読み取りができません(無効と見なされます)。
B19 move-result<kind> 命令は、(insns 配列内で)invoke-<kind> 命令の直後に配置する必要があります。ただし、move-result-object 命令は唯一の例外で、filled-new-array 命令の後に配置することもできます。
B20 move-result<kind> 命令は、(実際の制御フロー内で)一致する return-<kind> 命令の直後に配置する必要があります(直接ジャンプすることはできません)。ただし、move-result-object 命令は唯一の例外で、filled-new-array 命令の後に配置することもできます。
B21 move-exception 命令は、必ず例外ハンドラ内の最初の命令として配置する必要があります。
B22 packed-switch-datasparse-switch-datafill-array-data の各擬似命令は、制御フローからアクセスすることはできません。