What causes this error : java.lang.VerifyError: Inconsistent stack height 2 != 1?
-
21-12-2019 - |
Question
I use ASM to generate byte code for while() statement. But eclipse reports:
Exception in thread "main" java.lang.VerifyError: (class: show_cise_image, method: main signature: ([Ljava/lang/String;)V) Inconsistent stack height 2 != 1
at java.lang.Class.getDeclaredMethods0(Native Method)
..................
My source code for byte code:
show_cise_image {
boolean flag;
flag = true;
while(flag){
flag = false;
}
}
generated byte code for above code:
/ class version 51.0 (51)
// access flags 0x21
public class show_cise_image {
// access flags 0x8
static int v = 0
// access flags 0x8
static boolean flag = 0
// access flags 0x9
public static main(String[]) : void
L0
LINENUMBER 6 L0
GETSTATIC show_cise_image.flag : boolean
LDC 1
PUTSTATIC show_cise_image.flag : boolean
GOTO L1
L2
GETSTATIC show_cise_image.flag : boolean
LDC 0
PUTSTATIC show_cise_image.flag : boolean
L1
GETSTATIC show_cise_image.flag : boolean
IFNE L2
RETURN
L3
LOCALVARIABLE args String[] L0 L3 2
LOCALVARIABLE x int L0 L3 0
LOCALVARIABLE y int L0 L3 1
MAXSTACK = 3
MAXLOCALS = 3
}
my java code to generate byte code(I think this error is caused by while() statement, so I just post this part):
/* while(Expr){ stmt*} */
@Override
public Object visitIterationStmt(IterationStmt iterationStmt, Object arg)
throws Exception {
MethodVisitor mv = (MethodVisitor)arg;
Label guardLabel = new Label();
Label bodyLabel = new Label();
mv.visitJumpInsn(GOTO, guardLabel);
mv.visitLabel(bodyLabel);
for(Stmt t : iterationStmt.stmtList)
t.visit(this, mv); // execute statements in body
mv.visitLabel(guardLabel);
iterationStmt.expr.visit(this, mv); // put the result of expr on stack
mv.visitJumpInsn(IFNE, bodyLabel);
return null;
}
Solution
Lets analyze your bytecode manually:
L0 ; on entry stack is empty
LINENUMBER 6 L0
GETSTATIC show_cise_image.flag : boolean ; pushes a value, stack height is 1
LDC 1 ; pushes a value, stack heighe is 2
PUTSTATIC show_cise_image.flag : boolean ; pop 1 value, stack height is 1
GOTO L1 ; stack height 1 on going to L1...
L1 ; stack height 1 from previous goto
GETSTATIC show_cise_image.flag : boolean ; pushes a value, stack height is 2
IFNE L2 ; pops 1 value for test, stack height 1 on branch
L2 ; stack height 1 from previous branch
GETSTATIC show_cise_image.flag : boolean ; pushes a value, stack height is 2
LDC 0 ; pushes a value, stack height is 3
PUTSTATIC show_cise_image.flag : boolean ; pops a value, stack height is 2
; fall through to L1 with stack height 2
So you have an inconsistent stack depth on two paths to L1
, causing the verify error you see.
It seems to me, your error is the useless 'GETSTATIC' bytecodes in the blocks at L0
and L2
-- you're pushing the value of flag
on the stack, but never doing anything with it.
OTHER TIPS
This is because of the built in tomcat compiler.
The Java compiler from Eclipse JDT in included as the default compiler. It is an advanced Java compiler which will load all dependencies from the Tomcat class loader, which will help tremendously when compiling on large installations with tens of JARs. On fast servers, this will allow sub-second recompilation cycles for even large JSP pages.
If any such issues is seen follow the below workaround
Apache Ant, which was used in previous Tomcat releases, can be used instead of the new compiler by simply removing the lib/ecj-*.jar file, and placing the ant.jar and ant-launcher.jar files from the latest Ant distribution in the lib folder.