2015-12-28 1 views
3

Я использую ASM 5.0.3 байт-код библиотеки с Tomcat 8 и JDK 8. Также я используюASM - java.lang.VerifyError: Операнд переполнение стека исключений

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

и

classReader.accept(myClassVisitor, ClassReader.SKIP_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: Я также попытался использовать просто COMPUTE_FRAMES как в:

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

и я опустил ниже заявление SKIP_FRAMES:

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

Я по-прежнему получать ту же самую "Caused by: java.lang.VerifyError: Operand stack overflow" ошибку.

Edit # 2: Я попробовал все из следующих комбинаций и я получаю ту же ошибку: java.lang.VerifyError: Operand stack overflow Reason:Exceeded max stack size.

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

Edit # 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); 
    } 
} 

}

+0

Просто глядя на документы флагов 'ClassWriter' и' ClassReader', вы должны использовать 'COMPUTE_FRAMES' для автора и' SKIP_FRAMES' для читателя, а затем 'visitMaxs' будет проигнорирован. Исключение показывает, что стек пуст ('stack: {}'), поэтому я не знаю, почему это превысит максимальный размер стека ... –

ответ

0

Попробуйте использовать TraceClassVisitor, чтобы увидеть, где он становится перепутались. По моему опыту это происходит, когда метка написана неправильно, заставляя ее писать команды jsr/ret (JVM должен просто отвергать класс в этом случае, хотя вместе с сбоем asm при вычислении фреймов) и чаще всего забывает вызвать visitMaxs в методVisitor перед вызовом visitEnd. В моем коде я использую

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

Я не помню, что мои рассуждения для этого, что было, но мой ClassWriter работает, когда я делаю, но я надеюсь, что это помогает.

+0

Привет, Джеймс, Спасибо за ваш ответ .. В моем случае я использую совет, в котором я вызываю visitMaxs перед вызовом visitEnd. Поделитесь моим адаптером для справки. Это может помочь решить проблему. –

+0

Джеймс - отправил код адаптера. –

+0

Я был бы так счастлив опубликовать свой адаптер, но мне нужно получить разрешение, прежде чем я смогу это сделать, поэтому следите за ним. –

Смежные вопросы