Limitaciones

Un archivo .dex es el formato de transporte para el código de bytes de Dalvik. Existen ciertas restricciones sintácticas y semánticas para que un archivo sea un archivo .dex válido, y se requiere un entorno de ejecución para admitir solo archivos .dex válidos.

Restricciones generales de integridad de .dex

Las restricciones de integridad generales se relacionan con la estructura más grande de un archivo .dex, como se describe en detalle en el formato .dex.

Identificador Descripción
G1 El número magic del archivo .dex debe ser dex\n035\0 para la versión 35 o similar para versiones posteriores.
G2 La suma de verificación debe ser una suma de verificación Adler-32 del contenido completo del archivo, excepto los campos magic y checksum.
G3 La firma debe ser un hash SHA-1 de todo el contenido del archivo, excepto magic, checksum y signature.
G4

El file_size debe coincidir con el tamaño real del archivo en bytes. (v40 o anterior)

El file_size debe apuntar al siguiente encabezado en el contenedor o al final del archivo físico (el contenedor). Si apunta al siguiente encabezado, el tamaño del archivo debe estar alineado en 4 bytes. La suma de todos los campos file_size debe ser igual a container_size. (v41 o versiones posteriores)

G5

header_size debe tener el valor 0x70. (v40 o versiones anteriores)

header_size debe tener el valor 0x78. (v41 o versiones posteriores)

G6 endian_tag debe tener el valor ENDIAN_CONSTANT o REVERSE_ENDIAN_CONSTANT.
G7

Para cada una de las secciones link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs y data, los campos offset y size deben ser cero o no serlo. En el último caso, el desplazamiento debe estar alineado con cuatro bytes.

Los campos offset y size deben estar dentro del contenedor y hacer referencia a los datos que se encuentran después del encabezado que los define. (v41 o versiones posteriores)

G8 Todos los campos de offset en el encabezado, excepto map_off, deben estar alineados en cuatro bytes.
G9 El campo map_off debe ser cero o apuntar a la sección de datos. En el último caso, debe existir la sección data.
G10 Ninguna de las secciones link, string_ids, type_ids, proto_ids, field_ids, method_ids, class_defs y data debe superponerse entre sí ni con el encabezado.
G11 Si existe un mapa, cada entrada del mapa debe tener un tipo válido. Cada tipo puede aparecer una vez como máximo.
G12 Si existe un mapa, cada entrada del mapa debe tener un desplazamiento y un tamaño que no sean cero. El desplazamiento debe apuntar a la sección correspondiente del archivo (es decir, un string_id_item debe apuntar a la sección string_ids) y el tamaño explícito o implícito del elemento debe coincidir con el contenido y el tamaño reales de la sección.
G13 Si existe un mapa, el desplazamiento de la entrada del mapa n+1 debe ser mayor o igual que el desplazamiento de la entrada del mapa n plus than size of map entry n. Esto implica entradas que no se superponen y un orden de bajo a alto.
G14 Los siguientes tipos de entradas deben tener un desplazamiento alineado con cuatro bytes: string_id_item, type_id_item, proto_id_item, field_id_item, method_id_item, class_def_item, type_list, code_item y annotations_directory_item.
G15

Para cada string_id_item, el campo string_data_off debe contener una referencia válida en la sección data. (v40 o anterior)

Para cada string_id_item, el campo string_data_off debe ser un desplazamiento dentro del contenedor y después de cualquier encabezado que lo use de forma transitiva. (v41 o versiones posteriores)

Para el string_data_item al que se hace referencia, el campo data debe contener una cadena MUTF-8 válida y utf16_size debe coincidir con la longitud decodificada de la cadena.

G16 Para cada type_id_item, el campo descriptor_idx debe contener una referencia válida en la lista string_ids. La cadena a la que se hace referencia debe ser un descriptor de tipo válido.
G17 Para cada proto_id_item, el campo shorty_idx debe contener una referencia válida en la lista string_ids. La cadena a la que se hace referencia debe ser un descriptor de atajo válido. Además, el campo return_type_idx debe ser un índice válido en la sección type_ids, y el campo parameters_off debe ser cero o un desplazamiento válido que apunte a la sección data. Si no es igual a cero, la lista de parámetros no debe contener ninguna entrada nula.
G18 Para cada field_id_item, los campos class_idx y type_idx deben ser índices válidos en la lista type_ids. La entrada a la que hace referencia class_idx debe ser un tipo de referencia que no sea de array. Además, el campo name_idx debe ser una referencia válida en la sección string_ids, y el contenido de la entrada a la que se hace referencia debe cumplir con la especificación MemberName.
G19 Para cada method_id_item, el campo class_idx debe ser un índice válido en la sección type_ids, y la entrada a la que se hace referencia debe ser un tipo de referencia que no sea de array. El campo proto_id debe ser una referencia válida en la lista proto_ids. El campo name_idx debe ser una referencia válida en la sección string_ids, y el contenido de la entrada a la que se hace referencia debe cumplir con la especificación MemberName.
G20 Para cada field_id_item, el campo class_idx debe ser un índice válido en la lista type_ids. La entrada a la que se hace referencia debe ser un tipo de referencia que no sea de array.

Restricciones de código de bytes estáticas

Las restricciones estáticas son restricciones en elementos individuales del código de bytes. Por lo general, se pueden verificar sin emplear técnicas de control ni análisis de flujo de datos.

Identificador Descripción
A1 El array insns no debe estar vacío.
A2 La primera operación de código en el array insns debe tener el índice cero.
A3 El array insns solo debe contener códigos de operación de Dalvik válidos.
A4 El índice de la instrucción n+1 debe ser igual al índice de la instrucción n más la longitud de la instrucción n, teniendo en cuenta los posibles operandos.
A5 La última instrucción del array insns debe terminar en el índice insns_size-1.
A6 Todos los destinos de goto y if-<kind> deben ser opcodes dentro del mismo método.
A7 Todos los destinos de una instrucción packed-switch deben ser opcodes dentro del mismo método. El tamaño y la lista de objetivos deben ser coherentes.
A8 Todos los destinos de una instrucción sparse-switch deben ser opcodes dentro del mismo método. La tabla correspondiente debe ser coherente y estar ordenada de menor a mayor.
A9 El operando B de las instrucciones const-string y const-string/jumbo debe ser un índice válido en el grupo de constantes de cadenas.
A10 El operando C de las instrucciones iget<kind> y iput<kind> debe ser un índice válido en el grupo de constantes de campo. La entrada a la que se hace referencia debe representar un campo de instancia.
A11 El operando C de las instrucciones sget<kind> y sput<kind> debe ser un índice válido en el grupo de constantes de campo. La entrada a la que se hace referencia debe representar un campo estático.
A12 El operando C de las instrucciones invoke-virtual, invoke-super, invoke-direct y invoke-static debe ser un índice válido en el grupo de constantes del método.
A13 El operando B de las instrucciones invoke-virtual/range, invoke-super/range, invoke-direct/range y invoke-static/range debe ser un índice válido en el grupo de constantes del método.
A14 La VM solo debe invocar de forma implícita un método cuyo nombre comienza con "<", no con código proveniente de un archivo .dex. La única excepción es el inicializador de instancias, que puede invocar invoke-direct.
A15 El operando C de la instrucción invoke-interface debe ser un índice válido en el grupo de constantes del método. El method_id al que se hace referencia debe pertenecer a una interfaz (no a una clase).
A16 El operando B de la instrucción invoke-interface/range debe ser un índice válido en el grupo de constantes del método. El method_id al que se hace referencia debe pertenecer a una interfaz (no a una clase).
A17 El operando B de las instrucciones const-class, check-cast, new-instance y filled-new-array/range debe ser un índice válido en el grupo de constantes de tipo.
A18 El operando C de las instrucciones instance-of, new-array y filled-new-array debe ser un índice válido en el grupo de constantes de tipo.
A19 Las dimensiones de un array creado por una instrucción new-array deben ser menores que 256.
A20 La instrucción new no debe hacer referencia a clases de array, interfaces ni clases abstractas.
A21 El tipo al que hace referencia una instrucción new-array debe ser un tipo válido que no sea de referencia.
A22 Todos los registros a los que hace referencia una instrucción de un solo ancho (no en pares) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y menores que registers_size.
A23 Todos los registros a los que hace referencia una instrucción de doble ancho (par) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y menores que registers_size-1.
A24 El operando method_id de las instrucciones invoke-virtual y invoke-direct debe pertenecer a una clase (no a una interfaz). En los archivos Dex anteriores a la versión 037, lo mismo debe ser cierto para las instrucciones invoke-super y invoke-static.
A25 El operando method_id de las instrucciones invoke-virtual/range y invoke-direct/range debe pertenecer a una clase (no a una interfaz). En los archivos Dex anteriores a la versión 037, lo mismo debe ser cierto para las instrucciones invoke-super/range y invoke-static/range.

Restricciones de código de bytes estructurales

Las restricciones estructurales son restricciones en las relaciones entre varios elementos del código de bytes. Por lo general, no se pueden verificar sin emplear técnicas de control o análisis de flujo de datos.

Identificador Descripción
B1 La cantidad y los tipos de argumentos (registros y valores inmediatos) siempre deben coincidir con la instrucción.
B2 Los pares de registro nunca deben dividirse.
B3 Primero, se debe asignar un registro (o par) para poder leerlo.
B4 Una instrucción invoke-direct debe invocar un inicializador de instancia o un método solo en la clase actual o en una de sus superclases.
B5 Un inicializador de instancias solo se debe invocar en una instancia que no se inicializó.
B6 Los métodos de instancia solo se pueden invocar en campos de instancia y solo se puede acceder a instancias ya inicializadas.
B7 No se debe usar un registro que contenga el resultado de una instrucción new-instance si se vuelve a ejecutar la misma instrucción new-instance antes de que se inicialice la instancia.
B8 Un inicializador de instancias debe llamar a otro inicializador de instancias (misma clase o superclase) antes de que se pueda acceder a los miembros de la instancia. Las excepciones son campos de instancia no heredados, que se pueden asignar antes de llamar a otro inicializador, y la clase Object en general.
B9 Todos los argumentos de método reales deben ser compatibles con la asignación con sus argumentos formales respectivos.
B10 Para cada invocación de método de instancia, la instancia real debe ser compatible con la asignación de la clase o interfaz especificada en la instrucción.
B11 Una instrucción return<kind> debe coincidir con el tipo de datos que se muestra del método.
B12 Cuando se accede a miembros protegidos de una superclase, el tipo real de la instancia a la que se accede debe ser la clase actual o una de sus subclases.
B13 El tipo de un valor almacenado en un campo estático debe ser compatible con la asignación o convertible al tipo del campo.
B14 El tipo de un valor almacenado en un campo debe ser compatible con la asignación o debe poder convertirse al tipo del campo.
B15 El tipo de cada valor almacenado en un array debe ser compatible con la asignación del tipo de componente del array.
B16 El operando A de una instrucción throw debe ser compatible con la asignación de java.lang.Throwable.
B17 La última instrucción accesible de un método debe ser una goto o una rama hacia atrás, una return o una instrucción throw. No debe ser posible dejar el array insns en la parte inferior.
B18 Es posible que no se pueda leer la mitad no asignada de un par de registros anterior (se considera no válida) hasta que otra instrucción la vuelva a asignar.
B19 Una instrucción move-result<kind> debe anteceder inmediatamente (en el array insns) a una instrucción invoke-<kind>. La única excepción es la instrucción move-result-object, que también puede estar precedida por una instrucción filled-new-array.
B20 Una instrucción move-result<kind> debe estar inmediatamente precedida (en el flujo de control real) por una instrucción return-<kind> coincidente (no se debe omitir). La única excepción es la instrucción move-result-object, que también puede estar precedida por una instrucción filled-new-array.
B21 Una instrucción move-exception debe aparecer solo como la primera instrucción en un controlador de excepciones.
B22 El flujo de control no debe poder alcanzar las pseudoinstrucciones packed-switch-data, sparse-switch-data ni fill-array-data.