限制

.dex檔案是 Dalvik 字節碼的傳輸格式。要使文件成為有效的.dex文件,存在某些語法和語義約束,並且運行時需要僅支援有效的 .dex 文件。

一般 .dex 完整性約束

一般完整性約束與.dex檔案的較大結構有關,如.dex格式中詳細描述的。

識別符描述
G1 .dex檔的magic數必須是dex\n035\0dex\n037\0
G2校驗和必須是除magicchecksum和欄位之外的整個文件內容的 Adler-32 校驗和。
G3簽章必須是整個檔案內容的 SHA-1 雜湊值( magicchecksumsignature除外)。
G4 file_size必須與實際檔案大小(以位元組為單位)相符。
G5 header_size值必須為: 0x70
G6 endian_tag必須具有以下值之一: ENDIAN_CONSTANTREVERSE_ENDIAN_CONSTANT
G7對於每個linkstring_idstype_idsproto_idsfield_idsmethod_idsclass_defsdata部分, offsetsize欄位必須皆為零或均非零。在後一種情況下,偏移量必須是四位元組對齊的。
G8除了map_off之外,標頭中的所有偏移欄位都必須是四位元組對齊的。
G9 map_off欄位必須為零或指向資料部分。在後一種情況下, data部分必須存在。
G10 linkstring_idstype_idsproto_idsfield_idsmethod_idsclass_defsdata部分都無法互相重疊或與標頭重疊。
G11如果存在映射,則每個映射條目必須具有有效類型。每種類型最多出現一次。
G12如果存在映射,則每個映射條目必須具有非零偏移量和大小。偏移量必須指向檔案的相應部分(即string_id_item必須指向string_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
G15對於每個string_id_itemstring_data_off欄位必須包含對data部分的有效引用。對於引用的string_data_itemdata欄位必須包含有效的 MUTF-8 字串,且utf16_size必須與字串的解碼長度相符。
G16對於每個type_id_itemdescriptor_idx欄位必須包含對string_ids列表的有效引用。引用的字串必須是有效的型別描述符。
G17對於每個proto_id_itemshorty_idx欄位必須包含對string_ids列表的有效引用。引用的字串必須是有效的短描述符。此外, return_type_idx欄位必須是type_ids部分的有效索引,且parameters_off欄位必須為零或指向data部分的有效偏移量。如果非零,則參數清單不得包含任何空白條目。
G18對於每個field_id_itemclass_idxtype_idx欄位都必須是type_ids清單中的有效索引。 class_idx引用的條目必須是非數組參考類型。此外, name_idx欄位必須是string_ids部分的有效引用,且引用條目的內容必須符合MemberName規格。
G19對於每個method_id_itemclass_idx欄位必須是type_ids部分的有效索引,且所引用的條目必須是非數組參考類型。 proto_id欄位必須是proto_ids清單的有效引用。 name_idx欄位必須是string_ids部分的有效引用,且引用條目的內容必須符合MemberName規範。
G20對於每個field_id_itemclass_idx欄位必須是type_ids清單中的有效索引。引用的條目必須是非數組引用類型。

靜態字節碼約束

靜態約束是對字節碼的各個元素的約束。通常無需使用控製或資料流分析技術即可檢查它們。

識別符描述
A1 insns數組不能為空。
A2 insns數組中的第一個操作碼的索引必須為零。
A3 insns陣列必須僅包含有效的 Dalvik 操作碼。
A4考慮到可能的操作數,指令n+1的索引必須等於指令n的索引加上指令n的長度。
A5 insns數組中的最後一條指令必須以索引insns_size-1結束。
A6所有gotoif-<kind>目標必須是同一方法內的操作碼。
A7 packed-switch指令的所有目標必須是同一方法內的操作碼。目標的大小和清單必須一致。
A8 sparse-switch指令的所有目標必須是同一方法內的操作碼。對應的表必須一致,並且從低到高排序。
A9 const-stringconst-string/jumbo指令的B操作數必須是字串常數池中的有效索引。
A10 iget<kind>iput<kind>指令的C操作數必須是欄位常數池中的有效索引。引用的條目必須代表實例欄位。
A11 sget<kind>sput<kind>指令的C操作數必須是欄位常數池中的有效索引。引用的條目必須表示靜態欄位。
A12 invoke-virtualinvoke-superinvoke-directinvoke-static指令的C操作數必須是方法常數池的有效索引。
A13 invoke-virtual/rangeinvoke-super/rangeinvoke-direct/rangeinvoke-static/range指令的B操作數必須是方法常數池中的有效索引。
A14名稱以“<”開頭的方法只能由 VM 隱式調用,而不能由源自.dex檔案的程式碼調用。唯一的例外是實例初始值設定項,它可以由invoke-direct呼叫。
A15 invoke-interface指令的C操作數必須是方法常數池的有效索引。引用的method_id必須屬於介面(而不是類別)。
A16 invoke-interface/range指令的B操作數必須是方法常數池的有效索引。引用的method_id必須屬於介面(而不是類別)。
A17 const-classcheck-castnew-instancefilled-new-array/range指令的B操作數必須是類型常數池的有效索引。
A18 instance-ofnew-arrayfilled-new-array指令的C操作數必須是類型常數池的有效索引。
A19new-array指令建立的陣列的維數必須小於256
A20 new指令不得引用數組類別、介面或抽象類別。
A21 new-array指令引用的型別必須是有效的非引用型別。
A22指令以單寬(非成對)方式引用的所有暫存器必須對目前方法有效。也就是說,它們的索引必須為非負且小於registers_size
A23指令以雙寬(對)方式引用的所有暫存器都必須對目前方法有效。也就是說,它們的索引必須為非負且小於registers_size-1
A24 invoke-virtualinvoke-direct指令的method_id操作數必須屬於類別(而非介面)。在版本037之前的 Dex 檔案中invoke-superinvoke-static指令也必須如此。
A25 invoke-virtual/rangeinvoke-direct/range指令的method_id運算元必須屬於類別(而非介面)。在版本037之前的 Dex 檔案中invoke-super/rangeinvoke-static/range指令也必須如此。

結構字節碼約束

結構約束是字節碼的多個元素之間的關係的約束。如果不使用控製或資料流分析技術,通常無法檢查它們。

識別符描述
B1參數(暫存器和立即值)的數量和類型必須始終與指令相符。
B2寄存器對決不能被分解。
B3必須先分配一個暫存器(或暫存器對),然後才能讀取它。
B4 invoke-direct指令必須僅呼叫目前類別或其超類別之一中的實例初始值設定項或方法。
B5實例初始值設定項只能在未初始化的實例上呼叫。
B6實例方法只能在已經初始化的實例上調用,實例欄位也只能在已經初始化的實例上存取。
B7如果在初始化實例之前再次執行相同的new-instance指令,則不得使用儲存new-instance指令結果的暫存器。
B8在存取任何實例成員之前,實例初始值設定項必須呼叫另一個實例初始值設定項(相同類別或超類別)。異常是非繼承的實例字段,可以在呼叫另一個初始值設定項之前分配,並且通常是Object類別。
B9所有實際方法參數必須與其各自的形式參數賦值相容。
B10對於每個實例方法調用,實際實例必須與指令中指定的類別或介面賦值相容。
B11 return<kind>指令必須與其方法的回傳類型相符。
B12當存取超類別的受保護成員時,所存取實例的實際類型必須是目前類別或其子類別之一。
B13儲存到靜態欄位中的值的類型必須與欄位的類型相容或可轉換。
B14儲存到欄位中的值的類型必須與欄位的類型相容或可轉換。
B15儲存到數組中的每個值的類型必須與數組的組件類型賦值相容。
B16 throw指令的A操作數必須與java.lang.Throwable賦值相容。
B17方法的最後一個可到達指令必須是向後goto或分支、 returnthrow指令。一定不能將insns數組留在底部。
B18前一個暫存器對的未分配的一半可能無法讀取(被視為無效),直到它被其他指令重新分配為止。
B19 move-result<kind>指令必須緊接在invoke-<kind>指令之前(在insns陣列中)。唯一的例外是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偽指令不能透過控制流程存取。