"VerifyError: StackMapTable error: bad offset" at the first instruction of a method in instrumented class
"VerifyError: StackMapTable error: bad offset" at the first instruction of a method in instrumented class
我使用 ASM 检测 class 文件,检测后的 class 抛出 VerifyError。错误消息如下:
java.lang.VerifyError: StackMapTable error: bad offset
Exception Details:
Location:
org/joda/time/TestAllPackages.suite()Ljunit/framework/Test; @0: invokestatic
Reason:
Invalid stackmap specification.
Current Frame:
bci: @88
flags: { }
locals: { }
stack: { }
Bytecode:
0x0000000: b800 5bb6 005f 3f1e 1276 b800 67bb 0002
0x0000010: 59b7 0003 4d2c b800 04b6 0005 2cb8 0006
0x0000020: b600 052c b800 07b6 0005 2cb8 0008 b600
0x0000030: 052c b800 09b6 0005 2cb8 000a b600 052c
0x0000040: b800 0bb6 0005 2c1e 1276 b800 74b0 a700
0x0000050: 0a1e 1276 b800 74bf
Exception Handler Table:
bci [0, 78] => handler: 81
Stackmap Table:
same_locals_1_stack_item_extended(@81,Object[#85])
same_frame(@88)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.createInstanceFromSuiteMethod(JUnit3Reflector.java:153)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.constructTestObject(JUnit3Reflector.java:124)
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:75)
at org.apache.maven.surefire.junit.JUnit3Provider.executeTestSet(JUnit3Provider.java:140)
at org.apache.maven.surefire.junit.JUnit3Provider.invoke(JUnit3Provider.java:113)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:379)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:340)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:125)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:413)
并且检测 class 相当简单:org.joda.time.TestAllPackages.class。我手动使用 visitFrames
插入了那些堆栈图帧(没有使用 COMPUTE_FRAMES 这很痛苦)因为我想自己正确编写 visitFrames
。
我真的很想知道发生了什么,即 class 文件有什么问题,因为我没有发现任何可疑的东西。
谢谢!
顺便说一句,我的检测代码是这样的:
...
private Label tryStart = new Label();
private Label tryEnd = new Label();
private Label catchStart = new Label();
private Label catchEnd = new Label();
public XxxMethodVisitor(MethodVisitor mv, String methodName, int access, String desc, String className, boolean isStatic, boolean isPublic) {
super(Config.ASM_VERSION, mv);
this.methodName = methodName;
this.className = className;
this.selfDesc = desc;
selfReturnType = Type.getReturnType(desc);
selfMethodId = String.format("%s%c%s%c%s", className, SEPARATOR, methodName, SEPARATOR, desc);
this.isStatic = isStatic;
this.isPublic = isPublic;
}
// start of the method
public void visitCode() {
mv.visitCode();
// mv.visitFrame(F_NEW, initLocals.length, initLocals, 0, new Object[]{});
mv.visitTryCatchBlock(tryStart, tryEnd, catchStart, "java/lang/Throwable");
mv.visitLabel(tryStart);
...
}
public void visitEnd() {
mv.visitLabel(tryEnd);
mv.visitJumpInsn(GOTO, catchEnd);
mv.visitLabel(catchStart);
// exception caught
mv.visitFrame(F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"});
...
mv.visitInsn(ATHROW);
mv.visitLabel(catchEnd);
mv.visitFrame(F_SAME, 0, null, 0, null);
super.visitEnd();
}
我不知道为什么验证错误会抱怨堆栈映射 table,当有一个更明显的问题时:goto
指令分支到偏移量 84,这只是经过 suite
方法的末尾。这是我在检查您链接到的 class 时发现的。验证错误的转储看起来不同,但它引用了“bci:@88”,这也是越界的。
我使用 ASM 检测 class 文件,检测后的 class 抛出 VerifyError。错误消息如下:
java.lang.VerifyError: StackMapTable error: bad offset
Exception Details:
Location:
org/joda/time/TestAllPackages.suite()Ljunit/framework/Test; @0: invokestatic
Reason:
Invalid stackmap specification.
Current Frame:
bci: @88
flags: { }
locals: { }
stack: { }
Bytecode:
0x0000000: b800 5bb6 005f 3f1e 1276 b800 67bb 0002
0x0000010: 59b7 0003 4d2c b800 04b6 0005 2cb8 0006
0x0000020: b600 052c b800 07b6 0005 2cb8 0008 b600
0x0000030: 052c b800 09b6 0005 2cb8 000a b600 052c
0x0000040: b800 0bb6 0005 2c1e 1276 b800 74b0 a700
0x0000050: 0a1e 1276 b800 74bf
Exception Handler Table:
bci [0, 78] => handler: 81
Stackmap Table:
same_locals_1_stack_item_extended(@81,Object[#85])
same_frame(@88)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.createInstanceFromSuiteMethod(JUnit3Reflector.java:153)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.constructTestObject(JUnit3Reflector.java:124)
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:75)
at org.apache.maven.surefire.junit.JUnit3Provider.executeTestSet(JUnit3Provider.java:140)
at org.apache.maven.surefire.junit.JUnit3Provider.invoke(JUnit3Provider.java:113)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:379)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:340)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:125)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:413)
并且检测 class 相当简单:org.joda.time.TestAllPackages.class。我手动使用 visitFrames
插入了那些堆栈图帧(没有使用 COMPUTE_FRAMES 这很痛苦)因为我想自己正确编写 visitFrames
。
我真的很想知道发生了什么,即 class 文件有什么问题,因为我没有发现任何可疑的东西。
谢谢!
顺便说一句,我的检测代码是这样的:
...
private Label tryStart = new Label();
private Label tryEnd = new Label();
private Label catchStart = new Label();
private Label catchEnd = new Label();
public XxxMethodVisitor(MethodVisitor mv, String methodName, int access, String desc, String className, boolean isStatic, boolean isPublic) {
super(Config.ASM_VERSION, mv);
this.methodName = methodName;
this.className = className;
this.selfDesc = desc;
selfReturnType = Type.getReturnType(desc);
selfMethodId = String.format("%s%c%s%c%s", className, SEPARATOR, methodName, SEPARATOR, desc);
this.isStatic = isStatic;
this.isPublic = isPublic;
}
// start of the method
public void visitCode() {
mv.visitCode();
// mv.visitFrame(F_NEW, initLocals.length, initLocals, 0, new Object[]{});
mv.visitTryCatchBlock(tryStart, tryEnd, catchStart, "java/lang/Throwable");
mv.visitLabel(tryStart);
...
}
public void visitEnd() {
mv.visitLabel(tryEnd);
mv.visitJumpInsn(GOTO, catchEnd);
mv.visitLabel(catchStart);
// exception caught
mv.visitFrame(F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"});
...
mv.visitInsn(ATHROW);
mv.visitLabel(catchEnd);
mv.visitFrame(F_SAME, 0, null, 0, null);
super.visitEnd();
}
我不知道为什么验证错误会抱怨堆栈映射 table,当有一个更明显的问题时:goto
指令分支到偏移量 84,这只是经过 suite
方法的末尾。这是我在检查您链接到的 class 时发现的。验证错误的转储看起来不同,但它引用了“bci:@88”,这也是越界的。