有人可以列出字节码验证器必须执行以保证程序正确性的主要任务吗?JVM 规范中是否定义了一组标准的、最小的职责?我还想知道验证是否跨越其他阶段,例如加载和初始化。
3 回答
该页面的大部分内容描述了类型安全的各个方面。要检查程序是否是类型安全的,验证者需要确定每个程序点的操作数堆栈中驻留的操作数类型,并确保它们与相应指令所期望的类型相匹配。
它验证的其他内容包括但不限于以下内容:
分支必须在方法的代码数组范围内。
所有控制流指令的目标都是指令的开始。在宽指令的情况下,宽操作码被认为是指令的开始,并且给出被该宽指令修改的操作的操作码不被认为是指令的开始。不允许分支到指令中间。
没有指令可以访问或修改索引大于或等于其方法指示它分配的局部变量数量的局部变量。
所有对常量池的引用都必须指向适当类型的条目。(例如,指令 getfield 必须引用一个字段。)
代码不会在指令中间结束。
执行不能脱离代码的末尾。
对于每个异常处理程序,受处理程序保护的代码的起点和终点必须位于指令的开头,或者在终点的情况下,紧接在代码的结尾之后。起点必须在终点之前。异常处理程序代码必须从有效指令开始,并且不能从被宽指令修改的操作码开始。
作为最后一步,验证器还执行数据流分析,以确保没有指令引用任何未初始化的局部变量。
或者,您可能想看看 James Gosling 的Java 语言环境白皮书。
字节码验证器遍历字节码,构造类型状态信息,验证所有字节码指令的参数类型。
该图显示了从 Java 语言源代码通过 Java 编译器到类加载器和字节码验证器,进而到包含解释器和运行时系统的 Java 虚拟机的数据流和控制流。重要的问题是 Java 类加载器和字节码验证器对字节码流的主要来源没有做出任何假设——代码可能来自本地系统,或者它可能已经在地球的中途传播。字节码验证器充当一种看门人:它确保传递给 Java 解释器的代码处于适合执行的状态,并且可以运行而不必担心破坏 Java 解释器。在通过验证者的测试之前,不允许以任何方式执行导入的代码。验证器完成后,
- 没有操作数堆栈上溢或下溢
- 已知所有字节码指令的参数类型总是正确的
- 已知对象字段访问是合法的——私有的、公共的或受保护的
虽然所有这些检查看起来都非常详细,但当字节码验证器完成工作时,Java 解释器可以继续进行,因为它知道代码将安全运行。了解这些属性会使 Java 解释器更快,因为它不需要检查任何东西。没有操作数类型检查和堆栈溢出检查。因此,口译员可以在不影响可靠性的情况下全速运行。
它执行以下操作:
- 没有操作数堆栈上溢或下溢
- 已知所有字节码指令的参数类型总是正确的
- 已知对象字段访问是合法的——私有的、公共的或受保护的
参考:http: //java.sun.com/docs/white/langenv/Security.doc3.html