1.先来了解下字节码校验在类加载流程中的位置
当类加载器将新加载的Java平台类的字节码传递到虚拟机时,这些字节码首先要接受校验器的校验。校验器负责检查那些无法执行的明显有破坏性的操作。除了系统类之外,其他类都要被校验。
2.字节码校验器主要做的事情
- 变量要在使用之前进行初始化
- 方法调用与对象引用类型之前要匹配
- 访问私有数据和方法的规则没有被违背
- 对本地变量的访问落在运行时堆栈内
- 运行时堆栈没有溢出
3.例子(来源Java核心技术卷二)
package verifier; public class VerifierTest { public static void main(String[] args) { System.out.println("1 + 2 == " + fun()); } /** * A function that computes 1 + 2. * @return 3, if the code has not been corrupted */ public static int fun() { int m; int n; m = 1; n = 2; // use hex editor to change to "m = 2" in class file int r = m + n; return r; } }
步骤1:编译VertifierTest.java类
步骤2:使用javap查看编辑器如何编译fun方法
fun方法对应的16进制值《The Java Virtual Machine Specification》中有写
使用UltraEdit编辑找到对应的字节码
步骤三:将指令3的istore_1改为istore_0,也就是说,将16进制编辑器中的3C改为3B并保存文件,然后运行
VerifierTest程序
修改之前效果图
修改之后效果图
这里可以看到虚拟机发现了修改,校验没有通过
步骤4:使用-noverify运行程序,表面上看返回了个随机数