奇怪的java.lang.VerifyError

时间:2014-02-12 10:09:54

标签: java hibernate jvm javassist

我使用Hibernate运行时类检测。 然而,发生了奇怪的错误:

Caused by: java.lang.VerifyError: Bad type on operand stack in method pkg.model.ValueList$1.<init>(Lpkg/model/ValueList;)V at offset 2
    at pkg.model.ValueList.<init>(ValueList.java:24)

我创建了自己的ClassLoader,它应用了转换和 用它来提升整个应用程序。 以下是应用转换的方法:

    private byte[] transform(byte[] original) {
        for (ClassFileTransformer transformer : transformers) {
            try {
                byte[] transformed = transformer.transform(this,
                        className, null, null, original);
                if (transformed != null) {
                    original = transformed;
                    classReader = new ClassReader(transformed);
                    try {
                        CheckClassAdapter.verify(classReader, true,
                            new PrintWriter(System.out));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } catch (IllegalClassFormatException e) {
                throw new RuntimeException(e);
            }
        }
        return original;
    }

我使用此类加载器运行应用程序并获得以下输出:

<init>(Lpkg/model/ValueList;)V
00000 ValueList$1 ValueList  :  :     ALOAD 0
00001 ValueList$1 ValueList  : ValueList$1  :     ALOAD 1
00002 ValueList$1 ValueList  : ValueList$1 ValueList  :     INVOKEVIRTUAL pkg/model/ValueList$1.$javassist_write_this$0 (Lpkg/model/ValueList;)V
00003 ValueList$1 ValueList  :  :     ALOAD 0
00004 ValueList$1 ValueList  : ValueList$1  :     INVOKESPECIAL java/util/AbstractList.<init> ()V
00005 ValueList$1 ValueList  :  :     RETURN

我认为偏移2没有错。 我们使用正确的this(ValueList $ 1)和正确的参数(ValueList)调用方法。 并且ASM也没有看到任何不好的事情,因为它的验证者没有例外。 为什么然后JVM验证程序拒绝这个字节码?

Hibernate版本是4.1.10.Final。 以下是与错误相关的代码部分:

public class ValueList {
    //...
    @Transient
    private List<Value> safeValues = new AbstractList<Value>() {
        // ...
    }
    //...
}

1 个答案:

答案 0 :(得分:2)

可能是错误消息具有误导性。 您对super()的调用不是构造函数体中的第一个语句。如果将字节代码转换回Java,它将如下所示:

class ValueListInner extends AbstractList<Value> {
    public ValueListInner(ValueList list) {
        javassist_write_this_outer(list);
        super();    
    }

    private void javassist_write_this_outer(ValueList list) {
        //...
    }
}

这不是有效的Java代码。 它应该看起来像这样:

<init>(Lpkg/model/ValueList;)V
00000 ValueList$1 ValueList  :  :     ALOAD 0
00001 ValueList$1 ValueList  : ValueList$1  :     INVOKESPECIAL java/util/AbstractList.<init> ()V
00002 ValueList$1 ValueList  :  :     ALOAD 0
00003 ValueList$1 ValueList  : ValueList$1  :     ALOAD 1
00004 ValueList$1 ValueList  : ValueList$1 ValueList  :     INVOKEVIRTUAL pkg/model/ValueList$1.$javassist_write_this$0 (Lpkg/model/ValueList;)V
00005 ValueList$1 ValueList  :  :     RETURN