Un file .dex
è il formato di trasporto per il bytecode Dalvik. Esistono alcuni vincoli sintattici e semantici affinché un file sia un file .dex
valido ed è necessario un runtime per supportare solo file .dex validi.
Vincoli generali di integrità del file .dex
I vincoli generali di integrità riguardano la struttura più ampia di un file .dex
, come descritto in dettaglio nel formato .dex
.
Identificatore | Descrizione |
---|---|
G1 | Il numero magic del file .dex deve essere dex\n035\0 o dex\n037\0 . |
G2 | Il checksum deve essere un checksum Adler-32 dell'intero contenuto del file eccetto magic e il campo checksum . |
G3 | La firma deve essere un hash SHA-1 dell'intero contenuto del file tranne magic , checksum e signature . |
G4 | file_size deve corrispondere alla dimensione effettiva del file in byte. |
G5 | header_size deve avere il valore: 0x70 |
G6 | L' endian_tag deve avere il valore: ENDIAN_CONSTANT o REVERSE_ENDIAN_CONSTANT |
G7 | Per ciascuna delle link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs e data , i campi offset e size devono essere entrambi zero o entrambi diversi da zero. In quest'ultimo caso, l'offset deve essere allineato a quattro byte. |
G8 | Tutti i campi offset nell'intestazione tranne map_off devono essere allineati a quattro byte. |
G9 | Il campo map_off deve essere zero o puntare nella sezione dati. In quest'ultimo caso la sezione data deve esistere. |
G10 | Nessuno dei link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs e le sezioni data devono sovrapporsi tra loro o con l'intestazione. |
G11 | Se esiste una mappa, ciascuna voce della mappa deve avere un tipo valido. Ciascun tipo può apparire al massimo una volta. |
G12 | Se esiste una mappa, ciascuna voce della mappa deve avere un offset e una dimensione diversi da zero. L'offset deve puntare alla sezione corrispondente del file (cioè string_id_item deve puntare alla sezione string_ids ) e la dimensione esplicita o implicita dell'elemento deve corrispondere al contenuto effettivo e alla dimensione della sezione. |
G13 | Se esiste una mappa, l'offset della voce della mappa n+1 deve essere maggiore o uguale all'offset della voce della mappa n plus than size of map entry n . Ciò implica voci non sovrapposte e un ordinamento dal basso all'alto. |
G14 | I seguenti tipi di voci devono avere un offset allineato a quattro byte: 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 . |
G15 | Per ogni string_id_item , il campo string_data_off deve contenere un riferimento valido nella sezione data . Per string_data_item di riferimento, il campo data deve contenere una stringa MUTF-8 valida e utf16_size deve corrispondere alla lunghezza decodificata della stringa. |
G16 | Per ogni type_id_item , il campo descriptor_idx deve contenere un riferimento valido nell'elenco string_ids . La stringa di riferimento deve essere un descrittore di tipo valido. |
G17 | Per ogni proto_id_item , il campo shorty_idx deve contenere un riferimento valido nell'elenco string_ids . La stringa di riferimento deve essere un descrittore breve valido. Inoltre, il campo return_type_idx deve essere un indice valido nella sezione type_ids e il campo parameters_off deve essere zero o un offset valido che punta alla sezione data . Se diverso da zero, l'elenco dei parametri non deve contenere voci nulle. |
G18 | Per ogni field_id_item , entrambi i campi class_idx e type_idx devono essere indici validi nell'elenco type_ids . La voce a cui fa riferimento class_idx deve essere un tipo di riferimento non array. Inoltre, il campo name_idx deve essere un riferimento valido nella sezione string_ids e il contenuto della voce di riferimento deve essere conforme alla specifica MemberName . |
G19 | Per ogni method_id_item , il campo class_idx deve essere un indice valido nella sezione type_ids e la voce a cui si fa riferimento deve essere un tipo di riferimento non array. Il campo proto_id deve essere un riferimento valido nell'elenco proto_ids . Il campo name_idx deve essere un riferimento valido nella sezione string_ids e il contenuto della voce di riferimento deve essere conforme alla specifica MemberName . |
G20 | Per ogni field_id_item , il campo class_idx deve essere un indice valido nell'elenco type_ids . La voce a cui si fa riferimento deve essere un tipo di riferimento non array. |
Vincoli statici del bytecode
I vincoli statici sono vincoli sui singoli elementi del bytecode. Di solito possono essere controllati senza impiegare tecniche di controllo o di analisi del flusso di dati.
Identificatore | Descrizione |
---|---|
A1 | L'array insns non deve essere vuoto. |
A2 | Il primo codice operativo nell'array insns deve avere indice zero. |
A3 | L'array insns deve contenere solo codici operativi Dalvik validi. |
A4 | L'indice dell'istruzione n+1 deve essere uguale all'indice dell'istruzione n più la lunghezza dell'istruzione n , tenendo conto dei possibili operandi. |
A5 | L'ultima istruzione nell'array insns deve terminare con l'indice insns_size-1 . |
A6 | Tutti i target goto e if-<kind> devono essere codici operativi all'interno dello stesso metodo. |
A7 | Tutti i target di un'istruzione packed-switch devono essere codici operativi all'interno dello stesso metodo. La dimensione e l'elenco degli obiettivi devono essere coerenti. |
A8 | Tutti i target di un'istruzione sparse-switch devono essere codici operativi all'interno dello stesso metodo. La tabella corrispondente deve essere coerente e ordinata dal basso verso l'alto. |
A9 | L'operando B delle istruzioni const-string e const-string/jumbo deve essere un indice valido nel pool di costanti di stringa. |
A10 | L'operando C delle istruzioni iget<kind> e iput<kind> deve essere un indice valido nel pool di costanti di campo. La voce a cui si fa riferimento deve rappresentare un campo di istanza. |
A11 | L'operando C delle istruzioni sget<kind> e sput<kind> deve essere un indice valido nel pool di costanti di campo. La voce a cui si fa riferimento deve rappresentare un campo statico. |
A12 | L'operando C delle istruzioni invoke-virtual , invoke-super , invoke-direct e invoke-static deve essere un indice valido nel pool di costanti del metodo. |
A13 | L'operando B delle istruzioni invoke-virtual/range , invoke-super/range , invoke-direct/range e invoke-static/range deve essere un indice valido nel pool di costanti del metodo. |
A14 | Un metodo il cui nome inizia con "<" deve essere invocato solo implicitamente dalla VM, non dal codice proveniente da un file .dex . L'unica eccezione è l'inizializzatore dell'istanza, che può essere richiamato da invoke-direct . |
A15 | L'operando C dell'istruzione invoke-interface deve essere un indice valido nel pool di costanti del metodo. Il method_id a cui si fa riferimento deve appartenere a un'interfaccia (non a una classe). |
A16 | L'operando B dell'istruzione invoke-interface/range deve essere un indice valido nel pool di costanti del metodo. Il method_id a cui si fa riferimento deve appartenere a un'interfaccia (non a una classe). |
A17 | L'operando B delle istruzioni const-class , check-cast , new-instance filled-new-array/range deve essere un indice valido nel pool di costanti di tipo. |
A18 | L'operando C delle istruzioni instance-of , new-array filled-new-array deve essere un indice valido nel pool di costanti di tipo. |
A19 | Le dimensioni di un array creato da un'istruzione new-array devono essere inferiori a 256 . |
A20 | La new istruzione non deve fare riferimento a classi di array, interfacce o classi astratte. |
A21 | Il tipo a cui fa riferimento un'istruzione new-array deve essere un tipo valido, non di riferimento. |
A22 | Tutti i registri a cui fa riferimento un'istruzione in modalità a larghezza singola (non a coppia) devono essere validi per il metodo corrente. Cioè, i loro indici devono essere non negativi e inferiori a registers_size . |
A23 | Tutti i registri a cui fa riferimento un'istruzione in modo a doppia larghezza (coppia) devono essere validi per il metodo corrente. Cioè, i loro indici devono essere non negativi e più piccoli di registers_size-1 . |
A24 | L'operando method_id delle istruzioni invoke-virtual e invoke-direct deve appartenere a una classe (non a un'interfaccia). Nei file Dex precedenti alla versione 037 lo stesso deve valere per le istruzioni invoke-super e invoke-static . |
A25 | L'operando method_id delle istruzioni invoke-virtual/range e invoke-direct/range deve appartenere a una classe (non a un'interfaccia). Nei file Dex precedenti alla versione 037 lo stesso deve valere per le istruzioni invoke-super/range e invoke-static/range . |
Vincoli strutturali del bytecode
I vincoli strutturali sono vincoli sulle relazioni tra diversi elementi del bytecode. Di solito non possono essere controllati senza impiegare tecniche di controllo o di analisi del flusso di dati.
Identificatore | Descrizione |
---|---|
B1 | Il numero e il tipo di argomenti (registri e valori immediati) devono sempre corrispondere all'istruzione. |
B2 | Le coppie di registri non devono mai essere scisse. |
B3 | Un registro (o una coppia) deve essere assegnato prima di poter essere letto. |
B4 | Un'istruzione invoke-direct deve invocare un inizializzatore di istanza o un metodo solo nella classe corrente o in una delle sue superclassi. |
B5 | Un inizializzatore di istanza deve essere richiamato solo su un'istanza non inizializzata. |
B6 | I metodi dell'istanza possono essere invocati solo su e i campi dell'istanza sono accessibili solo su istanze già inizializzate. |
B7 | Un registro che contiene il risultato di un'istruzione new-instance non deve essere utilizzato se la stessa istruzione new-instance viene nuovamente eseguita prima che l'istanza venga inizializzata. |
B8 | Un inizializzatore di istanza deve chiamare un altro inizializzatore di istanza (stessa classe o superclasse) prima che sia possibile accedere a qualsiasi membro dell'istanza. Le eccezioni sono i campi di istanza non ereditati, che possono essere assegnati prima di chiamare un altro inizializzatore, e la classe Object in generale. |
B9 | Tutti gli argomenti effettivi del metodo devono essere compatibili con l'assegnazione con i rispettivi argomenti formali. |
B10 | Per ogni chiamata al metodo di istanza, l'istanza effettiva deve essere compatibile con l'assegnazione della classe o dell'interfaccia specificata nell'istruzione. |
B11 | Un'istruzione return<kind> deve corrispondere al tipo restituito del relativo metodo. |
B12 | Quando si accede ai membri protetti di una superclasse, il tipo effettivo dell'istanza a cui si accede deve essere la classe corrente o una delle sue sottoclassi. |
B13 | Il tipo di un valore archiviato in un campo statico deve essere compatibile con l'assegnazione o convertibile nel tipo del campo. |
B14 | Il tipo di un valore archiviato in un campo deve essere compatibile con l'assegnazione o convertibile nel tipo del campo. |
B15 | Il tipo di ogni valore archiviato in un array deve essere compatibile con l'assegnazione del tipo di componente dell'array. |
B16 | L'operando A di un'istruzione throw deve essere compatibile con l'assegnazione con java.lang.Throwable . |
B17 | L'ultima istruzione raggiungibile di un metodo deve essere un goto o un branch all'indietro, un return o un'istruzione throw . Non deve essere possibile lasciare l'array insns in fondo. |
B18 | La metà non assegnata di una precedente coppia di registri non può essere letta (è considerata non valida) finché non viene riassegnata da qualche altra istruzione. |
B19 | Un'istruzione move-result<kind> deve essere immediatamente preceduta (nell'array insns ) da un'istruzione invoke-<kind> . L'unica eccezione è l'istruzione move-result-object , che può anche essere preceduta da un'istruzione filled-new-array . |
B20 | Un'istruzione move-result<kind> deve essere immediatamente preceduta (nel flusso di controllo effettivo) da un'istruzione return-<kind> corrispondente (non deve essere saltata a essa). L'unica eccezione è l'istruzione move-result-object , che può anche essere preceduta da un'istruzione filled-new-array . |
B21 | Un'istruzione move-exception deve apparire solo come prima istruzione in un gestore di eccezioni. |
B22 | Le pseudoistruzioni packed-switch-data , sparse-switch-data e fill-array-data non devono essere raggiungibili dal flusso di controllo. |