如何在JVM中验证字节码?
答案 0 :(得分:19)
Oracle本身有一些关于其工作原理的摘要页here。
基本上,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 ===>>>
答案 1 :(得分:9)
最佳信息来源可能是JVM规范中的相关部分4.10 Verification of class Files。
有关详细信息,请参阅链接,但广泛地说:
链接时验证可提高解释器的性能。可以消除否则必须执行的昂贵检查以在运行时验证每个解释指令的约束。 Java虚拟机可以假定已经执行了这些检查。例如,Java虚拟机已经知道以下内容:
- 没有操作数堆栈溢出或下溢。
- 所有本地变量的使用和存储均有效。
- 所有Java虚拟机指令的参数都是有效类型。
验证程序还执行验证,无需查看代码属性的代码数组(第4.7.3节)即可完成验证。执行的检查包括以下内容:
- 确保最终类不是子类,并且不会覆盖最终方法(第5.4.5节)。
- 检查每个班级(
Object
除外)是否有直接超类。- 确保常量池满足记录的静态约束;例如,常量池中的每个
CONSTANT_Class_info
结构在其name_index
项中包含CONSTANT_Utf8_info
结构的有效常量池索引。- 检查常量池中的所有字段引用和方法引用是否具有有效名称,有效类和有效类型描述符。