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.
|