Ramesh Subramanian
Ramesh Subramanian

Reputation: 1037

ASM - java.lang.VerifyError: Operand stack overflow Exception

I am using ASM 5.0.3 byte code library with Tomcat 8 and JDK 8. Also I am using

ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES);

and

classReader.accept(myClassVisitor, ClassReader.SKIP_FRAMES);

Below exception is thrown by ASM

  Caused by: java.lang.VerifyError: Operand stack overflow
Exception Details:
  Location:      org/apache/tomcat/websocket/server/WsServerContainer.addEndpoint(Ljavax/websocket/server/ServerEndpointConfig;)V @0: aload_0
   Reason:
    Exceeded max stack size.
  Current Frame:
    bci: @0
    flags: { }
    locals: { 'org/apache/tomcat/websocket/server/WsServerContainer', 'javax/websocket/server/ServerEndpointConfig' }
    stack: { }
  Bytecode:
    0x0000000: 2ab4 000a 9900 1a2a b400 0b9a 0013 bb01
    0x0000010: 3d59 b200 4412 45b6 0046 b700 47bf 2ab4
    0x0000020: 000e c700 13bb 0043 59b2 0044 1248 b600
    0x0000030: 46b7 0047 bf2b b900 4901 004d bb00 4a59
    0x0000040: 2bb9 004b 0100 2bb9 004c 0100 2cb7 004d
    0x0000050: 4e2d b600 4ec7 0018 2db6 004f c700 112d
    0x0000060: b600 50c7 000a 2db6 0051 9900 122b b900
    0x0000070: 5201 0012 532d b900 5403 0057 bb00 5559
    0x0000080: 2cb7 0056 3a04 1904 b600 5799 0087 1904
    0x0000090: b600 58b8 0059 3a05 2ab4 0008 1905 b600
    0x00000a0: 5ac0 005b 3a06 1906 c700 29bb 005c 59b8
    0x00000b0: 005d b700 5e3a 062a b400 0819 0519 06b6
    0x00000c0: 005f 572a b400 0819 05b6 005a c000 5b3a
    0x00000d0: 0619 06bb 0060 592b 1904 b700 61b9 0062
    0x00000e0: 0200 9a00 2dbb 0043 59b2 0044 1263 06bd
    0x00000f0: 0064 5903 2c53 5904 2bb9 004b 0100 5359
    0x0000100: 052b b900 4b01 0053 b600 65b7 0047 bfa7
    0x0000110: 0043 2ab4 0007 2c2b b900 5403 00c0 0066
    0x0000120: 3a05 1905 c600 2ebb 0043 59b2 0044 1263
    0x0000130: 06bd 0064 5903 2c53 5904 1905 b900 4b01
    0x0000140: 0053 5905 2bb9 004b 0100 53b6 0065 b700
    0x0000150: 47bf 2a04 b500 0db1                    

    at org.apache.tomcat.websocket.server.WsSci.init(WsSci.java:131)
    at org.apache.tomcat.websocket.server.WsSci.onStartup(WsSci.java:47)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5244)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)

How to resolve this issue without using -noverify option?

Edit #1: I also tried using simply COMPUTE_FRAMES as in:

ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES);

and I omitted the below SKIP_FRAMES statement:

//classReader.accept(myClassVisitor, ClassReader.SKIP_FRAMES);

I continue to get the same "Caused by: java.lang.VerifyError: Operand stack overflow" error.

Edit #2: I have tried all of the following combinations and am getting the same error: java.lang.VerifyError: Operand stack overflow Reason:Exceeded max stack size.

  1. ClassWriter.COMPUTE_FRAMES with ClassReader.EXPAND_FRAMES and mv.visitMaxs(maxStack, maxLocals);
  2. ClassWriter.COMPUTE_FRAMES with ClassReader.EXPAND_FRAMES and mv.visitMaxs(-1, -1);
  3. ClassWriter.COMPUTE_FRAMES with ClassReader.SKIP_FRAMES and mv.visitMaxs(maxStack, maxLocals);
  4. ClassWriter.COMPUTE_FRAMES with ClassReader.SKIP_FRAMES and mv.visitMaxs(-1, -1);

Edit #3. Here is my Advice adapter code

public class PojoMethodAdviceAdapter extends AdviceAdapter  {
private String methodName;
private String className;
private String description;
private boolean excludeCheckFlag = false;
private int okFlag =  newLocal(Type.getType("Z")); //newLocal(Type.BOOLEAN_TYPE); 
private int classFileVersion;

Label startFinally = new Label();

private static Hashtable excludeMethods = new  Hashtable();
private static final String yesString = "Yes";
private boolean isValid;

static{
    excludeMethods.put("<clinit>", yesString);
    excludeMethods.put("<init>", yesString);
}

public PojoMethodAdviceAdapter(int access , MethodVisitor mv , String methodName, String description, String className, int classFileVersion){
    super(Opcodes.ASM5 , mv, access, methodName, description);
    this.className = className;
    this.methodName = methodName;
    this.description = description;
    this.excludeCheckFlag = true;
    this.isValid = true;
    this.classFileVersion = classFileVersion;

    String yesStr = (String)excludeMethods.get(this.methodName);
    if(yesStr!=null && yesStr.equals(yesString))
        isValid = false;
    if(this.methodName.indexOf("$") > 0)
        isValid = false;
    if(isValid){
        System.out.println(" [POJO MethodAdviceAdapter] :"+className+" \t "+methodName +" \t  "+description);
    }
}

public void visitCode() {
    super.visitCode(); 
    mv.visitLabel(startFinally);
}

protected void onMethodEnter(){
    if(isValid) {
        mv.visitInsn(Opcodes.ICONST_0);
        mv.visitVarInsn(ISTORE, okFlag);

        mv.visitLdcInsn(className);
        mv.visitLdcInsn(methodName);
        mv.visitLdcInsn(description);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/mini/agent/trace/RootTracer", "pojoMethodBegin", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z", false);
        mv.visitVarInsn(ISTORE, okFlag);
    }
}

protected void onMethodExit(int opcode){
    if(opcode!=ATHROW) {
        onFinally(opcode);
    }
}

public void visitMaxs(int maxStack, int maxLocals){
    Label endFinally = new Label();
    mv.visitTryCatchBlock(startFinally, endFinally, endFinally, null);
    mv.visitLabel(endFinally);
    onFinally(ATHROW);
    mv.visitInsn(ATHROW);
    if(classFileVersion <= 50){
        mv.visitMaxs(maxStack, maxLocals);
    }
    else{
        mv.visitMaxs(0, 0);
    }
}

private void onFinally(int opcode){
    if(isValid){
        if(opcode == ATHROW){
            mv.visitInsn(Opcodes.DUP);
            mv.visitLdcInsn(className);
            mv.visitLdcInsn(methodName);
            mv.visitLdcInsn(description);
            mv.visitVarInsn(ILOAD, okFlag);
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/mini/agent/trace/RootTracer", "recordPOJOException", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", false);
        }

        mv.visitLdcInsn(className);
        mv.visitLdcInsn(methodName);
        mv.visitLdcInsn(description);
        mv.visitVarInsn(ILOAD, okFlag);
        mv.visitLdcInsn(opcode);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/mini/agent/trace/RootTracer", "pojoMethodEnd", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZI)V", false);
    }
}

}

Upvotes: 3

Views: 5125

Answers (1)

James Ratzlaff
James Ratzlaff

Reputation: 39

Try using the TraceClassVisitor to see where it is getting messed up. In my experience this happens when a Label is written incorrectly, forcing it to write jsr/ret instructions (the JVM should simply reject the class in that case though along with asm crashing when calculating frames), and most often, forgetting to call visitMaxs in the methodVisitor before calling visitEnd. In my code I'm using

visitMaxs(mv.getMaxLocals(),mv.getMaxLocals());

I don't remember what my reasoning for doing that was but my ClassWriter works when I do, but I hope this helps.

Upvotes: 1

Related Questions