Question

I use Hibernate run time class instrumentation. Strange error happens however:

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)

I've created my own ClassLoader that applies transformations and use it to boostrap the whole application. Here is the method that applies transformations:

    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;
    }

I run application with this class loader and get the following output:

<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

I see nothing wrong at the offset 2. We call method with proper this (ValueList$1) and a proper argument (ValueList). And ASM sees nothing bad too, as its verifier throws no exceptions. Why then JVM verifier rejects this bytecode?

The Hibernate version is 4.1.10.Final. Here is the part of code that is related to the error:

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

Solution

May be the error message is misleading. Your call to super() is not the first statement in the constructor body. If you translate your byte code back to Java it will look something like this:

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

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

This is not a valid Java code. It should probably look like this:

<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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top