我正在使用带有Tomcat 8和JDK 8的ASM 5.0.3字节代码库。 我也在使用
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"
错误。
编辑#2 :我尝试了以下所有组合,并收到同样的错误:java.lang.VerifyError: Operand stack overflow Reason:Exceeded max stack size.
ClassWriter.COMPUTE_FRAMES
与ClassReader.EXPAND_FRAMES
和mv.visitMaxs(maxStack, maxLocals);
ClassWriter.COMPUTE_FRAMES
与ClassReader.EXPAND_FRAMES
和mv.visitMaxs(-1, -1);
ClassWriter.COMPUTE_FRAMES
与ClassReader.SKIP_FRAMES
和mv.visitMaxs(maxStack, maxLocals);
ClassWriter.COMPUTE_FRAMES
与ClassReader.SKIP_FRAMES
和mv.visitMaxs(-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);
}
}
}
答案 0 :(得分:0)
尝试使用TraceClassVisitor查看它搞砸了。根据我的经验,当Label被错误地写入时,会发生这种情况,迫使它写入jsr / ret指令(在这种情况下JVM应该简单地拒绝该类,尽管在计算帧时asm崩溃),并且通常,忘记调用visitMaxs in在调用visitEnd之前的methodVisitor。在我的代码中,我正在使用
visitMaxs(mv.getMaxLocals(),mv.getMaxLocals());
我不记得我的理由是什么,但是当我这样做时,我的ClassWriter会起作用,但我希望这会有所帮助。