`
RednaxelaFX
  • 浏览: 3015497 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

一个通不过Java字节码校验的例子

    博客分类:
  • Java
阅读更多
一般我们写Java源码,用Java编译器编译出.class文件,是不会碰到校验失败的状况的,因为正常的Java编译器都会小心对待生成的代码。所以,想要看到校验失败的状况,很容易的一个办法就是自己生成不合法的字节码。

这里我用了ObjectWeb的ASM来生成字节码。可以从官网下载asm-3.1.jar,并保证其在编译和运行下面这个程序时在classpath上。
(本来是很想顺便试试Charles O. Nutter写的bitescript库,不过惰性上来了,懒得去下载……下次吧,下次)
import java.io.FileOutputStream;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class TestASM implements Opcodes {
    public static void main(String[] args) throws Exception {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(
            V1_5,               // class format version
            ACC_PUBLIC,         // class modifiers
            "TestVerification", // class name fully qualified name
            null,               // generic signature
            "java/lang/Object", // super class fully qualified name
            new String[] { }    // implemented interfaces
        );
        
        MethodVisitor mv = cw.visitMethod(
            ACC_PUBLIC, // access modifiers
            "foo",      // method name
             "()V",     // method descriptor
             null,      // generic signature
             null       // exceptions
        );
        mv.visitCode();
        mv.visitInsn(FCONST_0);
        mv.visitVarInsn(FSTORE, 1);
        mv.visitVarInsn(ILOAD, 1);
        mv.visitVarInsn(ISTORE, 1);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 2);
        mv.visitEnd(); // end method
        
        cw.visitEnd(); // end class
        
        byte[] clz = cw.toByteArray();
        FileOutputStream out = new FileOutputStream("TestVerification.class");
        out.write(clz);
        out.close();
    }
}


运行该程序后,得到的是TestVerification.class文件,其内容是:
public class TestVerification extends java.lang.Object
  minor version: 0
  major version: 49
  Constant pool:
const #1 = Asciz        TestVerification;
const #2 = class        #1;     //  TestVerification
const #3 = Asciz        java/lang/Object;
const #4 = class        #3;     //  java/lang/Object
const #5 = Asciz        foo;
const #6 = Asciz        ()V;
const #7 = Asciz        Code;

{
public void foo();
  Code:
   Stack=1, Locals=2, Args_size=1
   0:   fconst_0
   1:   fstore_0
   2:   iload_0
   3:   istore_0
   4:   return

}

可以看到,foo()里代码先把float类型的常量0.0压到求值栈上(fconst_0),然后将它弹出并保存到局部存储区的第一格(fstore_0)。接下来从局部存储区的第一格取出一个int类型的值压到求值栈上(iload_0),再将其弹出并再次保存到局部存储区的第一格(istore_0)。

要是硬要用Java来表示这个.class文件里的逻辑,大概类似这样:
public class TestVerification {
    public void foo() {
        float a = 0;
        ((int) a) = a;
    }
}

很明显这没办法用Java表达出来……

上面代码中,局部存储区的第一格就在同一个方法里前后用于保存了float和int类型的值,破坏了类型安全。JVM为了保证类型安全,要求局部存储区里每格在上一次store与下一次load之间只能保存固定类型的值,load/store与对应的格的类型必须匹配;上一次load与下一次store的类型则并不要求一致。

运行这个程序会导致校验错误:
D:\temp_code>java TestVerification
Exception in thread "main" java.lang.VerifyError: (class: TestVerification, method: foo signature: ()V) Register 1 contains wrong type
Could not find the main class: TestVerification.  Program will exit.

于是JVM的类加载器先抱怨校验失败,然后拒绝加载这个main()方法,后面就连锁抱怨找不到main类。
分享到:
评论
5 楼 changcheng 2013-05-31  
RednaxelaFX 写道
changcheng 写道
问题找到了:

23:  iload_1 应该使用 aload_1

用JDK8的话在通不过bytecode verification时JVM会报出更详细的错误。可以下载现在的试用版来试试
http://openjdk.java.net/jeps/136


好的,我试试。这样会很方便,哈哈!
4 楼 RednaxelaFX 2013-05-23  
changcheng 写道
问题找到了:

23:  iload_1 应该使用 aload_1

用JDK8的话在通不过bytecode verification时JVM会报出更详细的错误。可以下载现在的试用版来试试
http://openjdk.java.net/jeps/136
3 楼 changcheng 2013-05-23  
问题找到了:

23:  iload_1 应该使用 aload_1
2 楼 changcheng 2013-05-23  
//==== 补充 javap -c
public void setHSFContainer(java.lang.Object);
  Code:
   0:   ldc     #2; //class com/taobao/hsf/log/impl/CallbackComponent
   2:   ldc     #51; //String setHSFContainer
   4:   ldc     #52; //String (Ljava/lang/Object;)V
   6:   invokestatic    #56; //Method com/tb/xman/common/hook/XManMethodCallBack.needHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Z

   9:   istore_2
   10:  iload_2
   11:  ifeq    29
   14:  ldc     #57; //int 1
   16:  anewarray       #4; //class java/lang/Object
   19:  astore_3
   20:  aload_3
   21:  ldc     #58; //int 0
   23:  iload_1
   24:  aastore
   25:  aload_3
   26:  invokestatic    #61; //Method com/tb/xman/common/hook/XManMethodCallBack.beforeMethod:([Ljava/lang/Object;)V
   29:  aload_0
   30:  aload_1
   31:  putfield        #20; //Field container:Ljava/lang/Object;
   34:  invokestatic    #23; //Method com/tb/xman/common/hook/XManMethodCallBack.beforeReturn:()V
   37:  return
1 楼 changcheng 2013-05-23  
//====== asm 生成的代码
public void setHSFContainer(Object container)
{
boolean flag = XManMethodCallBack.needHook(com/tb/hsf/log/impl/CallbackComponent, "setHSFContainer", "(Ljava/lang/Object;)V");
if(flag)
{
    Object aobj[] = new Object[1];
    aobj[0] = container;
    XManMethodCallBack.beforeMethod(aobj);
}
this.container = container;
XManMethodCallBack.beforeReturn();
}

//====== exception:

Exception in thread "main" java.lang.VerifyError: (class: com/tb/hsf/log/impl/CallbackComponent, method: setHSFContainer signature: (Ljava/lang/Object;)V) Register 1 contains wrong type
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
at java.lang.Class.getConstructor0(Class.java:2699)
at java.lang.Class.newInstance0(Class.java:326)
at java.lang.Class.newInstance(Class.java:308)
at com.tb.hsf.container.HSFContainer.initCallbackService(HSFContainer.java:242)
at com.tb.hsf.container.HSFContainer.start(HSFContainer.java:208)
at runjettyrun.Bootstrap.main(Bootstrap.java:220)


这个是什么原因呢?

相关推荐

    corejava基础重要知识点总结

    = 保镖 = 字节码校验器 = ByteCode Verifier = 翻译 = 解释执行器 = Interfreter 2:安全 健壮 电力 电信 银行 都会有限考虑使用java实现 3:免费 开源 4:简单 语法简单:c++-- (取其精华 去其糟粕) ...

    Java核心技术II(第8版)

    9.2 字节码校验 9.3 安全管理器与访问权限 9.3.1 Java 平台安全性 9.3.2 安全策略文件 9.3.3 定制权限 9.3.4 实现权限类 9.4 用户认证 9.4.1 JAAS 登录模块 9.5 数字签名 9.5.1 消息摘要 9.5.2 消息签名 9.5.3 X.509...

    Proguard下载|Proguard 5.3.1 官方最新版

    使字节码最大程度地优化,使用简短且无意义的名字来重命名类、字段和方法,截至2016-11-28号,5.3.1是最新版本 新的特性如下: 避免与库类混淆的名称冲突。 带有内部类的泛型签名的固定处理。 固定处理的通用...

    c#学习笔记.txt

    如前所述,我是一个狮子座男人,一度我认为学习Java会使我看起来与众不同,可是几个月以后我放弃了这个选择,我看了论坛里关于这两种语言孰优孰劣的讨论,最终选择了C#,请不要问我为何做出这样的选择,很多人认为...

    Spring.3.x企业应用开发实战(完整版).part2

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    Spring3.x企业应用开发实战(完整版) part1

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    正则表达式

    /\s+java\s+/ //匹配字符串"java" ,并且该串前后可以有一个或多个空格. /[^"] * / //匹配零个或多个非引号字符. 正则表达式的复制字符 字符 含义 ________________________________________________________...

    mysql官方中文参考手册

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    MYSQL中文手册

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用...

    MySQL 5.1参考手册中文版

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用...

    MySQL 5.1参考手册

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    MySQL5.1参考手册官方简体中文版

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    MySQL 5.1中文手冊

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    MySQL 5.1参考手册 (中文版)

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

    mysql5.1中文手册

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. ...

    MySQL 5.1官方简体中文参考手册

    在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 ...

Global site tag (gtag.js) - Google Analytics