Restricciones

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

Restricciones generales de integridad de .dex

Las restricciones generales de integridad están relacionadas 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 o dex\n037\0 .
G2 La suma de verificación debe ser una suma de verificación Adler-32 de todo el contenido del archivo, excepto el campo magic y de checksum de verificación.
G3 La firma debe ser un hash SHA-1 de todo el contenido del archivo excepto magic , checksum y signature .
G4 El file_size del archivo debe coincidir con el tamaño real del archivo en bytes.
G5 El header_size debe tener el valor: 0x70
G6 La 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 de offset y size deben ser cero o distintos de cero. En el último caso, el desplazamiento debe estar alineado con cuatro bytes.
G8 Todos los campos de compensación en el encabezado, excepto map_off , deben estar alineados con cuatro bytes.
G9 El campo map_off debe ser cero o apuntar a la sección de datos. En este último caso, la sección de data debe existir.
G10 Ninguna de las secciones link , string_ids , type_ids , proto_ids , field_ids , method_ids , class_defs y data debe superponerse entre sí o con el encabezado.
G11 Si existe un mapa, cada entrada del mapa debe tener un tipo válido. Cada tipo puede aparecer como máximo una vez.
G12 Si existe un mapa, cada entrada del mapa debe tener un desplazamiento y un tamaño distintos de 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 real y el tamaño de la sección.
G13 Si existe un mapa, entonces el desplazamiento de la entrada de mapa n+1 debe ser mayor o igual al desplazamiento de la entrada de mapa n plus than size of map entry n . Esto implica entradas no superpuestas y ordenación de menor a mayor.
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 , 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 . Para el string_data_item al que se hace referencia, el campo de 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 abreviado 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 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 matriz. 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 matriz. El campo proto_id debe ser una referencia válida en la lista de 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 matriz.

Restricciones de código de bytes estático

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

identificador Descripción
A1 La matriz insns no debe estar vacía.
A2 El primer código de operación en la matriz insns debe tener índice cero.
A3 La matriz insns debe contener solo códigos de operación 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 en la matriz insns debe terminar en el índice insns_size-1 .
A6 Todos los destinos goto e if-<kind> deben ser códigos de operación dentro del mismo método.
A7 Todos los objetivos de una instrucción packed-switch deben ser códigos de operación dentro del mismo método. El tamaño y la lista de objetivos deben ser consistentes.
A8 Todos los objetivos de una instrucción sparse-switch deben ser códigos de operación dentro del mismo método. La tabla correspondiente debe ser consistente y 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 conjunto de constantes de cadena.
A10 El operando C de las iget<kind> e iput<kind> debe ser un índice válido en el conjunto de constantes de campo. La entrada a la que se hace referencia debe representar un campo de instancia.
A11 El operando C de las sget<kind> y sput<kind> debe ser un índice válido en el conjunto 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 e invoke-static debe ser un índice válido en el conjunto de constantes del método.
A13 El operando B de las instrucciones invoke-virtual/range , invoke-super/range , invoke-direct/range e invoke-static/range debe ser un índice válido en el conjunto de constantes del método.
A14 Un método cuyo nombre comienza con '<' solo debe ser invocado implícitamente por la máquina virtual, no por el código que se origina en un archivo .dex . La única excepción es el inicializador de instancias, que puede ser invocado por invoke-direct .
A15 El operando C de la instrucción de la invoke-interface debe ser un índice válido en el conjunto 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 conjunto 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 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 nueva matriz filled-new-array debe ser un índice válido en el conjunto de constantes de tipo.
A19 Las dimensiones de una matriz creada por una instrucción new-array deben ser menores que 256 .
A20 La new instrucción no debe hacer referencia a clases de matriz, interfaces o 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 ancho simple (sin pares) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y más pequeños que registers_size .
A23 Todos los registros a los que hace referencia una instrucción en forma de doble ancho (par) deben ser válidos para el método actual. Es decir, sus índices deben ser no negativos y más pequeños que registers_size-1 .
A24 El operando method_id de las instrucciones invoke-virtual e invoke-direct debe pertenecer a una clase (no a una interfaz). En los archivos Dex anteriores a la versión 037 , lo mismo debe ocurrir con las instrucciones de invoke-super e invoke-static .
A25 El operando method_id de las instrucciones invoke-virtual/range e 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 de invoke-super/range e invoke-static/range .

Restricciones de bytecode estructural

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 El número y tipos de argumentos (registros y valores inmediatos) siempre deben coincidir con la instrucción.
B2 Los pares de registros nunca deben romperse.
B3 Primero se debe asignar un registro (o par) antes de que se pueda leer.
B4 Una instrucción de invocació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 instancia debe invocarse solo en una instancia no inicializada.
B6 Los métodos de instancia solo se pueden invocar y los campos de instancia solo se pueden acceder en instancias ya inicializadas.
B7 Un registro que contenga el resultado de una instrucción new-instance no se debe utilizar si la misma instrucción new-instance se vuelve a ejecutar antes de inicializar la instancia.
B8 Un inicializador de instancia debe llamar a otro inicializador de instancia (misma clase o superclase) antes de que se pueda acceder a cualquier miembro de la instancia. Las excepciones son los 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étodos reales deben ser compatibles con la asignación de sus respectivos argumentos formales.
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 retorno de su método.
B12 Al acceder a los 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 convertible al tipo del campo.
B15 El tipo de cada valor almacenado en una matriz debe ser compatible con la asignación con el tipo de componente de la matriz.
B16 El operando A de una instrucción throw debe ser compatible con la asignación con java.lang.Throwable .
B17 La última instrucción alcanzable de un método debe ser una instrucción de goto o salto hacia atrás, una instrucción de return o de throw . No debe ser posible dejar la matriz insns en la parte inferior.
B18 La mitad no asignada de un par de registros anterior no puede leerse (se considera inválida) hasta que haya sido reasignada por alguna otra instrucción.
B19 Una instrucción move-result<kind> debe estar inmediatamente precedida (en la matriz insns ) por una instrucción invocar- 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 saltar). 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 tener acceso a las pseudoinstrucciones packed-switch-data , sparse-switch-data y fill-array-data .