Vincoli

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

file_size deve corrispondere alle dimensioni effettive del file in byte. (v40 o versioni precedenti)

file_size deve puntare all'intestazione successiva nel contenitore o alla fine del file fisico (il contenitore). Se punta all'intestazione successiva, le dimensioni del file devono essere allineate a 4 byte. La somma di tutti i campi file_size deve essere uguale a container_size. (v41 o successive)

G5

header_size deve avere il valore: 0x70 (v40 o precedenti)

header_size deve avere il valore: 0x78 (v41 o successive)

G6 endian_tag deve avere il valore: ENDIAN_CONSTANT o REVERSE_ENDIAN_CONSTANT
G7

Per ogni sezione link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs e data, i campi offset e size devono essere entrambi pari a zero o entrambi diversi da zero. In quest'ultimo caso, l'offset deve essere alinhato a quattro byte.

I campi offset e size devono trovarsi all'interno del contenitore e fare riferimento ai dati che si trovano dopo l'intestazione che li definisce. (v41 o successive)

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 string_id_item, il campo string_data_off deve contenere un riferimento valido alla sezione data. (v40 o versioni precedenti)

Per ogni string_id_item, il campo string_data_off deve essere un offset all'interno del contenitore e dopo qualsiasi intestazione che lo utilizzi in modo trasitivo. (v41 o successive)

Per string_data_item a cui si fa riferimento, il campo data deve contenere una stringa MUTF-8 valida e il utf16_size deve corrispondere alla lunghezza decodificata della stringa.

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.