如何在JVM中验证字节码?
如何在JVM中验证字节码?
Oracle自己有一个关于它如何在这里工作的小片段页面。
基本上,JRE不信任JDK。这是因为它不知道哪个JDK编译器创建了类文件。在验证之前,它将类文件视为恶意文件。
在此基础上,字节码验证是防止Sun所谓的“恶意编译器”的必要步骤。Sun自己的Java编译器确保Java源代码不违反安全规则,但是,当应用程序导入代码片段时,它实际上并不知道代码片段是否遵循Java语言规则以确保安全。换句话说,代码可能不是由值得信赖的Java编译器生成的。
在这种情况下,计算机上的 Java 运行时系统必须假定片段是坏的,并对其进行字节码验证。
Java 虚拟机在完成此验证过程之前甚至看不到字节码。在加载字节码时执行此操作还具有一个优点,即每次执行代码时都不需要执行大量的运行时检查。因为它已经过验证是正确的,所以它一旦开始运行,就可以比本来可以更快地运行。
链接图的格式副本如下:
<<<=== Unsafe / Safe ===>>>
\
+---------------+ +-------------------+
| Java source | +--> | Class loader | --+
+---------------+ | | Bytecode verifier | |
| | +-------------------+ |
V | / |
+---------------+ | \ V
| Java compiler | Network / +-------------------+
+---------------+ | \ | JVM/JIT |
| | / +-------------------+
V | \ |
+---------------+ | / V
| Java bytecode | --+ \ +-------------------+
+---------------+ / | Operating system |
\ +-------------------+
/ |
\ V
/ +-------------------+
\ | Hardware |
/ +-------------------+
\
<<<=== Unsafe / Safe ===>>>
最好的信息来源可能是 JVM 规范中的相关部分,4.10 类文件的验证。
有关详细信息,请参阅链接,但大致如下:
链接时间验证可提高解释器的性能。可以消除昂贵的检查,否则必须执行这些检查来验证每个解释指令运行时的约束。Java 虚拟机可以假定已执行这些检查。例如,Java 虚拟机已经知道以下内容:
- 没有操作数堆栈溢出或下溢。
- 所有局部变量的使用和存储都是有效的。
- 所有 Java 虚拟机指令的参数都是有效类型的。
验证程序还执行无需查看 Code 属性 (§4.7.3) 的代码数组即可完成的验证。执行的检查包括:
- 确保最终类未被子类化,并且最终方法未被覆盖 (§5.4.5)。
- 检查每个类(除了)都有一个直接超类。
Object
- 确保常量池满足记录的静态约束;例如,常量池中的每个结构在其项中都包含结构的有效常量池索引。
CONSTANT_Class_info
name_index
CONSTANT_Utf8_info
- 检查常量池中的所有字段引用和方法引用是否具有有效名称、有效类和有效类型描述符。