15

字节码如何在 JVM 中得到验证?

4

2 回答 2

21

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 ===>>>
于 2009-04-16T06:45:43.740 回答
9

最好的信息来源可能是 JVM 规范中的相关部分,4.10 Verification of class Files

有关详细信息,请参阅链接,但范围很广:

链接时验证提高了解释器的性能。可以消除在运行时必须执行的昂贵检查以验证每个解释指令的约束。Java 虚拟机可以假定已经执行了这些检查。例如,Java 虚拟机已经知道以下内容:

  • 没有操作数堆栈上溢或下溢。
  • 所有局部变量的使用和存储都是有效的。
  • 所有 Java 虚拟机指令的参数都是有效类型。

验证器还执行无需查看 Code 属性的代码数组即可完成的验证(第 4.7.3 节)。执行的检查包括以下内容:

  • 确保最终类没有子类化并且最终方法没有被覆盖(第 5.4.5 节)。
  • 检查每个类(除了Object)有一个直接的超类。
  • 确保常量池满足记录的静态约束;例如,CONSTANT_Class_info常量池中的每个结构在其name_index项中都包含一个结构的有效常量池索引CONSTANT_Utf8_info
  • 检查常量池中的所有字段引用和方法引用是否具有有效的名称、有效的类和有效的类型描述符。
于 2009-04-16T06:44:28.267 回答