제약 조건

.dex 파일은 Dalvik 바이트 코드의 전송 포맷입니다. 파일이 유효한 .dex 파일이 되기 위한 특정한 구문적 제약 조건과 의미적 제약 조건이 있으며, 유효한 .dex 파일만 지원하기 위한 런타임이 필요합니다.

일반 .dex 무결성 제약 조건

일반 무결성 제약 조건은 .dex 형식에 자세히 설명된 것처럼 .dex 파일의 대규모 구조와 관련이 있습니다.

식별자 설명
G1 .dex 파일의 magic 숫자는 dex\n035\0 또는 dex\n037\0이어야 합니다.
G2 체크섬은 magicchecksum 필드를 제외한 전체 파일 콘텐츠의 Adler-32 체크섬이어야 합니다.
G3 서명은 magic, checksum, signature를 제외한 전체 파일 콘텐츠의 SHA-1 해시여야 합니다.
G4 file_size는 바이트 단위의 실제 파일 크기와 일치해야 합니다.
G5 header_size는 값이 0x70이어야 합니다.
G6 endian_tag는 값이 ENDIAN_CONSTANT 또는 REVERSE_ENDIAN_CONSTANT 중 하나여야 합니다.
G7 link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs, data 섹션에서 offsetsize 필드는 모두 0이거나 모두 0이 아니어야 합니다. 후자의 경우 오프셋은 4바이트로 정렬되어야 합니다.
G8 헤더에서 map_off를 제외한 모든 오프셋 필드는 4바이트로 정렬되어야 합니다.
G9 map_off 필드는 0이거나 데이터 섹션을 가리켜야 합니다. 후자의 경우에는 data 섹션이 있어야 합니다.
G10 link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs, data 섹션 중 어느 섹션도 서로 겹치거나 헤더와 겹쳐서는 안 됩니다.
G11 지도가 있는 경우 각 지도 항목의 유형은 유효해야 합니다. 각 유형은 최대 한 번만 표시될 수 있습니다.
G12 지도가 있는 경우 각 지도 항목의 오프셋과 크기는 0이 아니어야 합니다. 오프셋은 파일의 관련 섹션을 가리켜야 하고(예: string_id_itemstring_ids 섹션을 가리켜야 함) 항목의 명시적 또는 암시적 크기는 섹션의 실제 콘텐츠 및 크기와 일치해야 합니다.
G13 지도가 있는 경우 지도 항목 n+1의 오프셋은 지도 항목 n plus than size of map entry n의 오프셋보다 크거나 같아야 합니다. 이는 항목이 중복되지 않고 오름차순으로 정렬됨을 의미합니다.
G14 string_id_item, type_id_item, proto_id_item, field_id_item, method_id_item, class_def_item, type_list, code_item, annotations_directory_item 유형의 항목은 오프셋이 4바이트로 정렬되어야 합니다.
G15 string_id_itemstring_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 필드는 0이거나 data 섹션을 가리키는 유효한 오프셋이어야 합니다. 0이 아닌 경우 매개변수 목록에는 무효한 항목이 있어서는 안 됩니다.
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 목록의 유효한 색인이어야 합니다. 참조된 항목은 비배열 참조 유형이어야 합니다.

정적 바이트 코드 제약 조건

정적 제약 조건은 바이트 코드의 개별 요소에 적용되는 제약 조건입니다. 일반적으로 정적 제약 조건은 제어 흐름 또는 데이터 흐름 분석 기법을 사용하지 않고 확인할 수 있습니다.

식별자 설명
A1 insns 배열은 비워 두면 안 됩니다.
A2 insns 배열에서 첫 번째 opcode는 색인이 0이어야 합니다.
A3 insns 배열은 유효한 Dalvik opcode만 포함해야 합니다.
A4 명령어 n+1의 색인은 가능한 피연산자를 고려할 때 명령어 n의 색인과 명령어 n의 길이를 더한 값과 같아야 합니다.
A5 insns 배열의 마지막 명령어는 색인 insns_size-1에서 끝나야 합니다.
A6 모든 goto 타겟과 if-<kind> 타겟은 동일한 메서드 내의 opcode여야 합니다.
A7 packed-switch 명령어의 모든 타겟은 동일한 메서드 내의 opcode여야 합니다. 타겟의 크기와 목록은 일관되어야 합니다.
A8 sparse-switch 명령어의 모든 타겟은 동일한 메서드 내의 opcode여야 합니다. 관련 테이블은 일관되고 오름차순으로 정렬되어야 합니다.
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-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 또는 분기이거나 return 또는 throw 명령어이어야 합니다. insns 배열을 하단에 둘 수 없어야 합니다.
B18 이전 레지스터 쌍 중 할당되지 않은 절반은 다른 명령어에 의해 다시 할당될 때까지 읽을 수 없습니다(유효하지 않은 것으로 간주됨).
B19 insns 배열에서 move-result<kind> 명령어 바로 앞에는 invoke-<kind> 명령어가 와야 합니다. 단, move-result-object 명령어는 예외입니다. 이 명령어 앞에는 filled-new-array 명령어가 올 수도 있습니다.
B20 실제 제어 흐름에서 move-result<kind> 명령어 바로 앞에는 일치하는 return-<kind> 명령어가 와야 합니다(바로 건너뛸 수 없어야 함). 단, move-result-object 명령어는 예외입니다. 이 명령어 앞에는 filled-new-array 명령어가 올 수도 있습니다.
B12 move-exception 명령어는 예외 핸들러의 첫 번째 명령어로만 표시되어야 합니다.
B22 packed-switch-data, sparse-switch-datafill-array-data 의사 명령어는 제어 흐름을 통해 도달 가능해서는 안 됩니다.