Un file .dex è il formato di trasporto per il bytecode Dalvik. Esistono determinati vincoli sintattici e semantici per fare in modo che un file sia un file .dex valido ed è necessario un runtime per supportare solo file .dex validi.
Vincoli generali di integrità dei file .dex
I vincoli di integrità generali riguardano la struttura più grande 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 per la versione 35 o simile per le versioni successive.
|
| G2 |
Il checksum deve essere un checksum Adler-32 dell'intero contenuto del file
tranne i campi magic e checksum.
|
| G3 |
La firma deve essere un hash SHA-1 dell'intero contenuto del file, ad eccezione di magic, checksum e signature.
|
| G4 |
|
| G5 |
|
| G6 |
endian_tag deve avere il valore:
ENDIAN_CONSTANT o REVERSE_ENDIAN_CONSTANT
|
| G7 |
Per ogni sezione
I campi |
| G8 |
Tutti i campi di offset nell'intestazione, tranne map_off, devono essere allineati a quattro byte.
|
| G9 |
Il campo map_off deve essere pari a zero o fare riferimento alla sezione dei dati. In quest'ultimo caso, la sezione data deve esistere.
|
| G10 |
Nessuna delle sezioni link, string_ids,
type_ids, proto_ids, field_ids,
method_ids, class_defs e data
deve sovrapporsi l'una all'altra o all'intestazione.
|
| G11 | Se esiste una mappa, ogni voce della mappa deve avere un tipo valido. Ogni tipo può essere visualizzato al massimo una volta. |
| G12 |
Se esiste una mappa, ogni voce della mappa deve avere un offset e una dimensione diversi da zero. L'offset deve puntare alla sezione corrispondente del file (ad es. un
string_id_item deve puntare alla sezione string_ids) e le dimensioni esplicite o
implicite dell'elemento devono corrispondere ai contenuti e alle dimensioni effettivi 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 ordinamento da basso a alto.
|
| G14 |
I seguenti tipi di voci devono avere un offset alinhato su 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 Per ogni Per |
| G16 |
Per ogni type_id_item, il campo descriptor_idx deve contenere un riferimento valido all'elenco string_ids. La stringa a cui si fa riferimento deve essere un descrittore di tipo valido.
|
| G17 |
Per ogni proto_id_item, il campo shorty_idx deve contenere un riferimento valido all'elenco string_ids. La stringa a cui si fa riferimento deve essere un descrittore shorty valido. Inoltre, il campo return_type_idx deve essere un indice valido della sezione type_ids e il campo parameters_off deve essere zero o un offset valido che rimandi alla sezione data. Se diverso da zero, l'elenco dei parametri
non deve contenere voci vuote.
|
| G18 |
Per ogni field_id_item, sia i campi class_idx sia 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 alla sezione string_ids e i contenuti della voce di riferimento
devono essere conformi 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 alla sezione string_ids e i contenuti della voce a cui si fa riferimento devono essere conformi 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 di tipo
riferimento non array.
|
Vincoli del bytecode statico
I vincoli statici sono vincoli sui singoli elementi del bytecode. In genere possono essere controllati senza utilizzare tecniche di controllo o analisi del flusso di dati.
| Identificatore | Descrizione |
|---|---|
| A1 |
L'array insns non deve essere vuoto.
|
| A2 |
Il primo opcode nell'array insns deve avere indice zero.
|
| A3 |
L'array insns deve contenere solo opcode 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 all'indice
insns_size-1.
|
| A6 |
Tutti i target goto e if-<kind> devono essere opcode all'interno dello stesso metodo.
|
| A7 |
Tutti i target di un'istruzione packed-switch devono essere
opcode all'interno dello stesso metodo. Le dimensioni e l'elenco di target devono essere coerenti.
|
| A8 |
Tutti i target di un'istruzione sparse-switch devono essere
opcode all'interno dello stesso metodo. La tabella corrispondente deve essere
coerente e ordinata dal più basso al più 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 dei campi. La voce a cui si fa riferimento deve rappresentare un
campo istanza.
|
| A11 |
L'operando C delle istruzioni sget<kind> e
sput<kind> deve essere un indice valido nel
pool di costanti dei campi. 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 un "<" 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 invocato da invoke-direct.
|
| A15 |
L'operando C dell'istruzione invoke-interface
deve essere un indice valido nel pool di costanti del metodo. Il
valore method_id a cui viene fatto riferimento deve appartenere a un'interfaccia (non a un
oggetto).
|
| A16 |
L'operando B dell'istruzione invoke-interface/range
deve essere un indice valido nel pool di costanti del metodo.
Il riferimento a method_id deve appartenere a un'interfaccia (non a un
corso).
|
| A17 |
L'operando B delle istruzioni const-class,
check-cast, new-instance e
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 e 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 |
L'istruzione new 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à singola larghezza
(non a coppie) devono essere validi per il metodo corrente. In altre parole,
i relativi indici devono essere non negativi e inferiori a
registers_size.
|
| A23 |
Tutti i registri a cui fa riferimento un'istruzione in modalità a doppia larghezza (coppia) devono essere validi per il metodo corrente. In altre parole, i relativi indici
devono essere non negativi e inferiori a registers_size-1.
|
| 24A |
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
deve valere lo stesso 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
deve valere lo stesso per le istruzioni invoke-super/range e
invoke-static/range.
|
Vincoli del bytecode strutturale
I vincoli strutturali sono vincoli sulle relazioni tra diversi elementi del bytecode. In genere non possono essere controllati senza impiegare tecniche di controllo o di analisi del flusso di dati.
| Identificatore | Descrizione |
|---|---|
| B1 | Il numero e i tipi di argomenti (registri e valori immediati) devono sempre corrispondere all'istruzione. |
| B2 | Le coppie di registri non devono mai essere suddivise. |
| B3 | Prima di poter essere letto, un registro (o una coppia) deve essere assegnato. |
| 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 inizializzante dell'istanza deve essere invocato solo su un'istanza non inizializzata. |
| B6 | I metodi di istanza possono essere invocati solo su ed è possibile accedere ai campi di istanza 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 eseguita di nuovo prima
dell'inizializzazione dell'istanza.
|
| B8 |
Un inizializzante dell'istanza deve chiamare un altro inizializzante dell'istanza (stessa
classe o superclasse) prima che sia possibile accedere ai membri dell'istanza.
Le eccezioni sono campi di istanze non ereditati, che possono essere assegnati
prima di chiamare un altro inizializzante 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 dell'istanza, l'istanza effettiva deve essere compatibile con l'assegnazione con la classe o l'interfaccia specificata nell'istruzione. |
| B11 |
Un'istruzione return<kind> deve corrispondere al
tipo di ritorno del metodo.
|
| B12 | Quando accedi ai membri protetti di una superclasse, il tipo effettivo dell'istanza a cui si accede deve essere la classe corrente o uno dei suoi sottoclassi. |
| B13 | Il tipo di un valore memorizzato in un campo statico deve essere compatibile con l'assegnazione o convertibile nel tipo del campo. |
| B14 | Il tipo di un valore memorizzato in un campo deve essere compatibile con l'assegnazione o convertibile nel tipo del campo. |
| B15 | Il tipo di ogni valore memorizzato 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 ramo a ritroso, un return o un'istruzione throw. Non deve essere possibile lasciare
insns in fondo all'array.
|
| B18 | La metà non assegnata di una coppia di registri precedente non può essere letta (è considerata non valida) finché non viene riassegnata da un'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 eseguita un salto
a questa istruzione). L'unica eccezione è l'istruzione move-result-object, che può essere preceduta anche da un'istruzione filled-new-array.
|
| B21 |
Un'istruzione move-exception deve apparire solo come
prima istruzione in un gestore delle eccezioni.
|
| B22 |
Le pseudo-istruzioni packed-switch-data, sparse-switch-data e fill-array-data non devono essere raggiungibili dal flusso di controllo.
|