Class文件检查器保证装载的class文件内容有正确的内部结构,并且这些class文件互相间协调一致。Class文件检查器实现的安全目标之一就是程序的健壮性。如果某个有漏洞的编译器,或某个聪明的黑客,产生了一个class文件,而这个class文件中包含了一个方法,这个方法的字节码中含有一条跳转到方法之外的指令,那么,一旦这个方法被调用,它将导致虚拟机的崩溃,所以,处于对健壮性的考虑,由虚拟机检验它装载的字节码的完整性非常重要。
Class文件检验器在字节码执行之前,必须完成大部分检验土作。它只在执行前而不是在执行中对字节码进行一次分析(并检验它的完整性),每一次遇到一个跳转指令时都进行检验。作为字节码确认工作的一部分,虚拟机将确认所有的跳转指令会到达另一条合法的指令,而且这条指令是在这个方法的字节码流中的:在大多数情况下,在执行前就对所有字节码进行一次检查,对于保证健壮性来说就足够了,而不必在它运行时何次都检验每一条字节码指令
Class文件检查器要进行四趟独立的扫描来完成它的操作。
第一趟:Class文件的结构检查
在这一趟扫描中,对每一段将被当做class导入的字节序列,Class文件检查器都会确认它是否符合Java的Class文件的基本结构。在这一趟检查中,检查器会进行很多检查。例如:每个Class文件都必须以四个同样的字节开始:0xCAFEBABE。因为这个魔数Class文件分析器会很容易判断出某个文件具有明显问题而加以拒绝。检查器还必须确认在Class文件中声明的版本号和次版本号,这个版本号必须在这个虚拟机实现可以支持的范围之内。而且第一趟扫描还必须确认这个Class文件有没有被删减。虽然不同的class文件有不同的长度,但是在class文件中包含的每一个组成部分都声明了它的长度和类型。检验器可以使用class所有的组成部分的类型和长度来确定整个class文件的正确的总长度。用这种方法,它就可以检查一个装人的文件,其长度是否和它里面的内容相一致。
总之第一趟扫描的目的就是保证这个字节序列正确的定义了一个class。它必须遵从Java的class文件的固定格式,这样它才能被编译成在方法区中 的(基于实现的)内部数据结构。第二、第三和第四趟扫描不是在符合class文件格式的二进制数据上进行的,而是在方法区中,由实现决定的数据结构上进行 的。
第二趟:类型数据的语义检查
第二趟扫描,检查器要查看每个组成部分,确认它们是否是其所属类型的实例,它们的结构是否正确。例如,方法描述符(它的返回类型,以及参数的类型和个数)在class 文件中被存储为一个字符串.这个字符串必须符合特定的上卜文无关文法。检验器对每个组成部分进行检查的目的之一是,为了确认每个方法描述符都是符合特定语法的、格式正确的字符串。
另外,还要检查这个类本身是否符合由Java编程语言规定的特定条件。例如,检查器强制规定除Object类以外的类必须有一个超类,或者检查final类有没有被子化等。还要检查常量池中的条目是合法的,而且常量池的所有索引必须指向正确类型的常量池条目。也就是说,class 文件检验器在运行时检查了一些Java 语言应该在编译时遵守的强制规则。因为检验器并不能确定class 文件是否是由一个善意的、没有漏洞的编译器产生的,所以它会检查每个class 文件,以确保这些规则得到遵守。
第三趟:字节码验证
这一趟是要确保采用任何路径在字节码流中都得到一个确定的操作码,并确保操作数栈总是包含正确的数值以及正确的类型。
在Class 文件检验器成功地进行了两趟检查后,它将把注意力放在字节码上,这一趟扫描被称为“字节码验证”。在这趟扫描中,Java 虚拟机对字节码流进行分析,这些字节流代表的是类的方法所对应的JVM指令。字节码流其实是JVM指令的集合,它是由被称为操作码的单字节指令组成的序列,每一个操作码后都跟着1个或多个操作数。操作数用于在Java虚拟机执行操作码指令时提供所需的额外的数据。字节码检验器必须保证局部变量在赋予合适的值以前不能被访问,而且类的字段中 必须总是被赋子正确类型的值,类的方法被调用时总是传递正确数值和类型的参数。字节码检验器还必须保证每一个操作码都是合法的。也就是要保证每一个操作码 都有合法的操作数,以及对于每一个操作码,都有合适类型的数值位于局部变量中或是在操作数栈中。这些仅仅是字节码检验器所做的大量检验1 作中的一小部分,在整个检验过程通过后,它就能保证这个字节码流可以被Java 虚拟机安全地执行。
在第一、第二、第三趟扫描中,Class 文件检验器可以保证导人的class文件构成合理,内在一致,符合Java 编程语言的限制条件,并且包含的字节码可以被Java 虚拟机安全地执行。如果class 文件检验器发现其中任何一点不正确,它将会抛出一个错误,这个class文件将不会被程序使用。
第四趟:符号引用的验证
在动态链接的过程中,如果包含在一个Class文件中的符号引用被解析时,Class文件检查器要进行第四趟检查。
在这趟检查中,Java 虚拟机将追踪那些引用(从被验证的class到被它引用的class中),以确保这些引用是正确的。因为第四趟扫描要扫描被检查的class之外的class,所有这次扫描需要装载新的类。大多数Java 虚拟机的实现采用延迟装载类的策略,直到类真正地被程序使用时才装载。即使为了加快装载过程的速度,而确实预先装载了这些类,第四趟扫描还是会表现为延迟。例如,如果Java 虚拟机在预先装载中发现它不能找到某个特定的被引用类,它并不在当时抛出NotClassDefFoundError错误,而是直到(或者除非)这个被引用类首次被运行程序使用时才抛出。这样,如果Java 虚拟机进行预先连接,第四趟扫描可以紧随第三趟扫描发生。但是如果Java 虚拟机在某个符号引用第一次被使用时才进行解析,那么第四趟扫描将在第三趟扫描以后很久、当字节码被执行时才进行。
第四趟扫描仅仅是动态链接过程的一部分。当一个Class文件被装载时,它包含了对其他类的符号引用以及它们的字段和方法。一个符号引用是一个字符串,它给出了名字,并且可能还包含了其他关于这个被引用项的信息------这些信息必须足以唯一的识别一个类、方法、字段。这样对于其他类的符号引用必须给出这个类的全名;对于其他类的字段的符号引用必须给出类名、字段名以及字段描述符;对于其他类中的方法的引用必须给出类名、方法名以及方法的描述符。
所谓的动态链接是一个将符号引用解析为直接引用的过程。当Java虚拟机执行字节码时,如果它遇到一个操作码,而且这个操作码是第一次使用一个指向另一个类的符号引用,那么虚拟机就必须解析这个符号引用。在解析时,虚拟机执行两个基本任务:
A、查找被引用的类(如果必要的话就装载它)。
B、将符号引用替换为直接引用,例如一个指向类、字段或方法的指钊或偏移星。
虚拟机必须记住这个直接引用,这样当它以后再次遇到相同的引用时,它就可以立即使用这个直接引用,而不必花时间再次解析这个符号引用了。当Java虚拟机解析一个符号引用时,class 文件检验器的第四趟扫描确保了这个引用是合法的.如果这个引用是个非法引用(例如,这个类不能被装载,或这个类的确存在,但是不包含被引用的字段或方法)的话,class 文件检验器将抛出一个错误。
此外,由于Java程序是动态链接的,所以Class文件检查器在进行第四次扫描中,必须检查相互引用类之间的兼容性。如果你修改了一个类,Java编译器常 会重编译这些类,从而在编译时检测是否有任何的不兼容性。但是也有很多时候,编译器并不对受影响的类进行重编译,例如,如果正在开发一个大型系统,很可能 将系统分割成几个部分放人包中。如果对每个包进行独立的编译,当改动包中的一个类时,可能将导致对同一个包内受影响的那些类进行重新编译,但是对其他包中受影响的类并不进行重新编译。 此外如果使用了其他人的包时,尤其是程序在运行时通过网络下载了一些类,就不可能在编泽时检验兼容性。这就是为什么class文件检验器在第四趟扫描时,必须在运行时检查兼容性的原因。
- IOSerialize,xml和json,soap序列化器,二进制序列化器,XML序列化器,文件 检查、新增、复制、移动、删除
1 文件夹/文件 检查.新增.复制.移动.删除,2 文件读写,记录文本日志/读取配置文件3 三种序列化器4 xml和json1.文件夹/文件 检查.新增.复制.移动.删除,2 文件读写,记录文本日志/ ...
- sharepoint 2013 文档库 资源管理器打开报错 在文件资源管理器中打开此位置时遇到问题,将此网站添加到受信任站点列表,然后重试。
我们在使用sharepoint 2013的文档库或者资源库的时候,经常会需要用到使用“资源管理器”来管理文档,但是有时候,点击“使用资源管理器打开”,会提示如下错误: 在文件资源管理器中打开此位置时遇 ...
- python 拼写检查代码(怎样写一个拼写检查器)
原文:http://norvig.com/spell-correct.html 翻译:http://blog.youxu.info/spell-correct.html 怎样写一个拼写检查器 Pete ...
- Dicom格式文件解析器[转]
Dicom格式文件解析器 Dicom全称是医学数字图像与通讯,这里讲的暂不涉及通讯那方面的问题 只讲*.dcm 也就是diocm格式文件的读取,读取本身是没啥难度的 无非就是字节码数据流处理.只不 ...
- SQL Server 2005 无法连接到WMI提供程序 无法执行 SQL Server 系统配置检查器
无法连接到WMI提供程序.你没有权限或者该服务器无法访问/cannot connect to WMI provider. You do not have permission or the--由于计算 ...
- 如何写一个拼写检查器-by Peter Norvig
本文原著:Peter Norvig 中文翻译:徐宥 上个星期, 我的两个朋友 Dean 和 Bill 分别告诉我说他们对 Google 的快速高质量的拼写检查工具感到惊奇. 比如说在搜索的时候键入 ...
- excel保存时出现“请注意,您的文档的部分内容可能包含了文档检查器无法删除的个人信息”
这个问题的原因是由于工作簿包含宏.ActiveX控件等内容, 而Excel被设置为在保存文件时自动删除文件属性中的个人信息,因而出现该对话框.如果要避免出现这个提示,可进行如下设置: Excel 20 ...
- C++PE文件格式解析类(轻松制作自己的PE文件解析器)
PE是Portable Executable File Format(可移植的运行体)简写,它是眼下Windows平台上的主流可运行文件格式. PE文件里包括的内容非常多,详细我就不在这解释了,有兴趣 ...
- python 关于excel弹窗——请注意,您的文档的部分内容可能包含了文档检查器无法删除的个人信息解决方法
参考https://www.cnblogs.com/Jacklovely/p/6582732.html 这个问题的原因是由于工作簿包含宏.ActiveX控件等内容, 而Excel被设置为在保存文件时自 ...
随机推荐
- Java String Integer转换 练习:编程求字符串“100”和“150”按十进制数值做差后的结果以字符串形式输出。
package com.swift; public class String_To_Integer_Test { public static void main(String[] args) { /* ...
- runtime比较全面的总结
类和对象 Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者 ...
- 测试 code style
c++ #include <iostream> int main(int argc, char *argv[]) { /* An annoying "Hello World&qu ...
- 理解JS闭包的几个小实验
学了JavaScript有一段时间了,但是对闭包还是不太理解,于是怀着心中的疑问做了几个小实验,终于有点明白了. 首先看一下MDN上的定义:闭包是函数和声明该函数的词法环境的组合. 简单来说,闭包是一 ...
- 用宝塔软件在linux上自动安装php环境
1.确保是纯净系统 确保是干净的操作系统,没有安装过其它环境带的Apache/Nginx/php/MySQL,否则安装不上 2.sudo进行安装 yum install -y wget &&a ...
- python入门:while 循环的基本用法
#!/usr/bin/env python # -*- coding:utf-8 -*- #while 循环的作用 import time while True: ") time.sleep ...
- python入门:print打印输出的用法
#!/usr/bin/python # -*- coding:utf-8 -*- # print打印输出的用法 print("holle,world!") print(1) pri ...
- React 基础知识总结
data-id="1190000016885142" data-license=""> 一.Node.js Node.js并不是一个JavaScript框 ...
- laravel中使用PHPQuery实现网页采集
由于没有PHPQuery的composer包安装所以需要我们手动在我们的laravel项目中安装加载PHPQuery,这里需要设置laravel的autoload->class map. 1.首 ...
- POJ:2955-Brackets(经典:括号匹配)
传送门:http://poj.org/problem?id=2955 Brackets Time Limit: 1000MS Memory Limit: 65536K Description We g ...