Java 8 ASM-java.lang.VerifyError:操作数堆栈溢出异常

Java 8 ASM-java.lang.VerifyError:操作数堆栈溢出异常,java-8,java-bytecode-asm,Java 8,Java Bytecode Asm,我将ASM5.0.3字节代码库与Tomcat 8和JDK 8一起使用。 我也在用 ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES); 及 下面是ASM引发的异常 Caused by: java.lang.VerifyError: Operand stack overflow Exception Details: Location: org/apache/tomc

我将ASM5.0.3字节代码库与Tomcat 8和JDK 8一起使用。 我也在用

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

下面是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)
如何在不使用-noverify选项的情况下解决此问题

编辑#1:我还尝试使用simply COMPUTE#U帧,如下所示:

ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES);
我省略了下面的SKIP_FRAMES语句:

//classReader.accept(myClassVisitor, ClassReader.SKIP_FRAMES);
我继续得到相同的
,原因是:java.lang.VerifyError:Operator stack overflow“
错误

编辑#2:我尝试了以下所有组合,但得到了相同的错误:
java.lang.VerifyError:操作数堆栈溢出原因:超出了最大堆栈大小。

  • ClassWriter.COMPUTE_FRAMES
    ClassReader.EXPAND_FRAMES
    mv.visitmax(maxStack,maxLocals)
  • ClassWriter.COMPUTE_FRAMES
    ClassReader.EXPAND_FRAMES
    mv.visitmax(-1,-1)
  • ClassWriter.COMPUTE_FRAMES
    使用
    ClassReader.SKIP_FRAMES
    mv.visitmax(最大堆栈,最大局部变量)
  • ClassWriter.COMPUTE_FRAMES
    ClassReader.SKIP_FRAMES
    mv.visitmax(-1,-1)
  • 编辑#3。下面是我的建议适配器代码

    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);
        }
    }
    
    公共类PojoMethodAdviceAdapter扩展了AdviceAdapter{
    私有字符串methodName;
    私有字符串类名;
    私有字符串描述;
    私有布尔值excludeCheckFlag=false;
    private int-okFlag=newLocal(Type.getType(“Z”);//newLocal(Type.BOOLEAN_-Type);
    私有int类文件版本;
    标签开始最终=新标签();
    私有静态哈希表excludeMethods=新哈希表();
    私有静态最终字符串yesString=“Yes”;
    私有布尔值是有效的;
    静止的{
    excludeMethods.put(“,yesString”);
    excludeMethods.put(“,yesString”);
    }
    公共PojoMethodAdviceAdapter(int access、MethodVisitor mv、String methodName、String description、String className、int classFileVersion){
    超级(操作码ASM5、mv、访问、方法名称、描述);
    this.className=className;
    this.methodName=methodName;
    this.description=描述;
    this.excludeCheckFlag=true;
    this.isValid=true;
    this.classFileVersion=classFileVersion;
    String yesStr=(String)excludeMethods.get(this.methodName);
    如果(yesStr!=null&&yesStr.equals(yesString))
    isValid=false;
    if(this.methodName.indexOf(“$”)>0)
    isValid=false;
    如果(有效){
    System.out.println(“[POJO MethodAdviceAdapter]:”+className+“\t”+methodName+“\t”+说明);
    }
    }
    公共无效访问代码(){
    super.visitCode();
    mv.visitLabel(最终启动);
    }
    Methodenter()上的受保护的void{
    如果(有效){
    mv.visitInsn(操作码ICONST_0);
    mv.visitVarInsn(ISTORE,okFlag);
    mv.visitLdcInsn(类别名称);
    mv.visitLdcInsn(方法名称);
    mv.visitLdcInsn(说明);
    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);
    }
    }
    MethodExit上受保护的void(int操作码){
    if(操作码!=ATHROW){
    最终(操作码);
    }
    }
    公共void visitmax(int-maxStack、int-maxLocals){
    Label endFinally=新标签();
    mv.visittrychtblock(startFinally、endFinally、endFinally、null);
    mv.visitLabel(最终结束);
    最终(ATHROW);
    visitInsn号(ATHROW);
    
    if(classFileVersion尝试使用TraceClassVisitor查看哪里出错。根据我的经验,当标签写入错误时会发生这种情况,迫使它写入jsr/ret指令(在这种情况下,JVM应该简单地拒绝该类,尽管在计算帧时asm会崩溃),最常见的是,在调用visitEnd之前忘记调用methodVisitor中的visitMaxs

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

    我不记得我这样做的理由是什么,但我的ClassWriter在我这样做时起作用,但我希望这能有所帮助。

    只要看看
    ClassWriter
    ClassReader
    标志的文档,你就应该为编写者使用
    COMPUTE\u FRAMES
    ,为读者使用
    SKIP\u FRAMES
    ,然后使用
    visitMaxs
    将被忽略。异常显示堆栈为空(
    堆栈:{}
    ),所以我真的不知道为什么会超过任何最大堆栈大小…嗨,詹姆斯,谢谢你的回答..在我的情况下,我使用建议适配器,因为我在调用visitEnd之前确实调用了visitMaxs。将共享我的建议适配器..这可能有助于解决问题我非常乐意发布我的适配器,但我需要获得许可才能这样做,所以k请留心。除此之外,我发现您的try-catch-finally标签可能存在问题。我将查看我的代码以查看访问它们的顺序。在我的访问者中,我通过计算每个指令的字节长度来解决所有指令和标签偏移,然后根据访问优先级对每个标签进行排序d按偏移量进行二次排序,然后按顺序访问。我会看看是否能为您的问题找到更简单的解决方案。我99%肯定这就是您的问题的来源,因为我正在疯狂地试图找出我的代码为什么会从try-catch中中断。嗨,James,根据教程-我使用了try-catch-finally标签。它正在工作对于我来说,如果没有任何问题,Hey Ramesh,你能发布你生成的代码的javap输出吗?从我对输出的了解来看:第一条指令失败了,它是aload_0,下一条指令是索引0处的getField,在返回或抛出时,没有从堆栈中弹出内容。javap将帮助查看maxstack在字节码中添加了哪些值。
    visitMaxs(mv.getMaxLocals(),mv.getMaxLocals());