約束

.dex文件是 Dalvik 字節碼的傳輸格式。文件要成為有效的.dex文件有一定的語法和語義約束,並且運行時需要僅支持有效的 .dex 文件。

一般 .dex 完整性約束

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

標識符描述
G1 .dex文件的magic數必須是dex\n035\0dex\n037\0
G2校驗和必須是除magicchecksum字段外的整個文件內容的 Adler-32 校驗和。
G3簽名必須是除magicchecksum和和signature之外的整個文件內容的 SHA-1 哈希。
G4 file_size必須與實際文件大小(以字節為單位)匹配。
G5 header_size必須具有值: 0x70
G6 endian_tag必須具有以下值: ENDIAN_CONSTANTREVERSE_ENDIAN_CONSTANT
七國集團對於每個linkstring_idstype_idsproto_idsfield_idsmethod_idsclass_defsdata部分, offsetsize字段必須要么都是零,要么都是非零。在後一種情況下,偏移量必須是四字節對齊的。
八國集團除了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 的偏移量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 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偽指令。