machine - bytecode java ejemplos
Responsabilidades del verificador de código de bytes JVM (3)
Alternativamente, le gustaría echarle un vistazo al documento técnico Java Language Environment de James Gosling.
El verificador de bytecode atraviesa los bytecodes, construye la información de estado de tipo y verifica los tipos de parámetros en todas las instrucciones de bytecode.
La ilustración muestra el flujo de datos y control desde el código fuente del lenguaje Java a través del compilador de Java, al cargador de clases y al verificador de códigos de bytes y, por lo tanto, a la máquina virtual de Java, que contiene el intérprete y el sistema de tiempo de ejecución. El problema importante es que el cargador de clases de Java y el verificador de bytecode no hacen suposiciones acerca de la fuente principal del flujo de bytecode, ya que el código puede provenir del sistema local o puede haber viajado por la mitad del planeta. El verificador de bytecode actúa como una especie de controlador de acceso: garantiza que el código pasado al intérprete de Java se encuentre en un estado adecuado para ejecutarse y pueda ejecutarse sin temor a romper el intérprete de Java. El código importado no puede ejecutarse por ningún medio hasta que haya pasado las pruebas del verificador. Una vez que se realiza el verificador, se conocen una serie de propiedades importantes:
- No hay operandos de desbordamientos o desbordamientos de pila
- Se sabe que los tipos de parámetros de todas las instrucciones de código de bytes son siempre correctos
- Los accesos a campos de objetos son legales, privados, públicos o protegidos.
Si bien todas estas comprobaciones parecen extremadamente detalladas, en el momento en que el verificador de bytecode haya realizado su trabajo, el intérprete de Java puede continuar, sabiendo que el código se ejecutará de forma segura. Conocer estas propiedades hace que el intérprete de Java sea mucho más rápido, ya que no tiene que verificar nada. No hay comprobaciones de tipo de operandos ni comprobaciones de desbordamiento de pila. De este modo, el intérprete puede funcionar a toda velocidad sin comprometer la fiabilidad.
¿Podría alguien enumerar las tareas principales que debe realizar el verificador de bytecode para garantizar la corrección del programa? ¿Existe un conjunto mínimo y estándar de responsabilidades definido en la especificación de JVM? También me preguntaba si las verificaciones abarcan otras fases, como la carga y la inicialización.
Esto se especifica en la Especificación JVM: Capítulo 4.10. Verificación de archivos de clase .
La mayor parte de la página describe los diversos aspectos del tipo de seguridad. Para verificar que el programa es seguro para el tipo, el verificador necesita averiguar qué tipos de operandos residen en la pila de operandos en cada punto del programa, y asegurarse de que coincidan con el tipo esperado por la instrucción respectiva.
Otras cosas que verifica incluyen, pero no se limitan a lo siguiente:
Las ramas deben estar dentro de los límites de la matriz de código para el método.
Los objetivos de todas las instrucciones de control-flujo son cada uno el inicio de una instrucción. En el caso de una instrucción amplia, el código de operación amplio se considera el comienzo de la instrucción, y el código de operación que da la operación modificada por esa instrucción amplia no se considera para iniciar una instrucción. Las ramas en medio de una instrucción no están permitidas.
Ninguna instrucción puede acceder o modificar una variable local en un índice mayor o igual al número de variables locales que su método indica que asigna.
Todas las referencias a la agrupación constante deben ser a una entrada del tipo apropiado. (Por ejemplo, la instrucción getfield debe hacer referencia a un campo).
El código no termina en medio de una instrucción.
La ejecución no puede caer al final del código.
Para cada controlador de excepción, el punto de inicio y final del código protegido por el controlador debe estar al comienzo de una instrucción o, en el caso del punto final, inmediatamente después del final del código. El punto de partida debe ser anterior al punto final. El código del manejador de excepciones debe comenzar con una instrucción válida, y no debe comenzar con un código de operación modificado por la instrucción amplia.
Como paso final, el verificador también realiza un análisis de flujo de datos, lo que garantiza que ninguna instrucción haga referencia a ninguna variable local sin inicializar.
Hace lo siguiente:
- No hay operandos de desbordamientos o desbordamientos de pila
- Se sabe que los tipos de parámetros de todas las instrucciones de código de bytes son siempre correctos
- Los accesos a campos de objetos son legales, privados, públicos o protegidos.
Referencia: http://java.sun.com/docs/white/langenv/Security.doc3.html