Java.Lang.Verifyerror: Expecting a Stackmap Frame at Branch Target Jdk 1.7

java.lang.VerifyError: Expecting a stackmap frame at branch target

Hi this is related to some bytecode in your application. (see this note on compatibility changes for Java 7 http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#incompatibilities, look there some lines below for JSR 202)

You can either

  • recompile all sources with JDK 7
  • or in case you have no access to the source

    • use java with paramter -XX:-UseSplitVerifier
    • or switch to Java 6 if you face promblems using the switch

edit Even the answer is already a bit old. Because of a current case I add some more detailed explanation.

The StackMapTable attribute in the class file was, even not documented at that time, introduced with Java 6.

Foo.java

public class Foo {
public static boolean bar(String s) {
if (s.length() == 0) {
return true;
}
return false;
}
}

$ java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
$ javac Foo.java
$ javap -c -v Foo
Compiled from "Foo.java"
public class Foo extends java.lang.Object
SourceFile: "Foo.java"
minor version: 0
major version: 50
...
public static boolean bar(java.lang.String);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokevirtual #2; //Method java/lang/String.length:()I
4: ifne 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn
LineNumberTable:
line 3: 0
line 4: 7
line 6: 9

StackMapTable: number_of_entries = 1
frame_type = 9 /* same */
}

The class verifier did no check if the attribute was in the class or not.

Following creates the file Foo.class without the StackMatTable attribute.

FooDump.java

import org.objectweb.asm.*;
import java.io.*;

public class FooDump implements Opcodes {

public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("Foo.class");
fos.write(dump());
fos.close();
}

public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;

cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Foo", null, "java/lang/Object",
null);

MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,
null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V",
false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();

mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "bar",
"(Ljava/lang/String;)Z", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "length", "()I",
false);
Label l0 = new Label();
mv.visitJumpInsn(IFNE, l0);
mv.visitInsn(ICONST_1);
mv.visitInsn(IRETURN);
mv.visitLabel(l0);
// this line would generate the StackMapTable attribute
// mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(ICONST_0);
mv.visitInsn(IRETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();

cw.visitEnd();
return cw.toByteArray();
}
}

compile and run it

$ javac -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump.java
$ java -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump

check that the StackMapTable attribute is not in the file

$ javap -c -v Foo
public class Foo extends java.lang.Object
minor version: 0
major version: 50
...
public static boolean bar(java.lang.String);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokevirtual #16; //Method java/lang/String.length:()I
4: ifne 9
7: iconst_1
8: ireturn
9: iconst_0
10: ireturn
}

FooDemo.java

public class FooDemo {
public static void main(String[] args) {
System.out.println("output: " + Foo.bar(""));
}
}

$ java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
$ javac FooDemo.java
$java FooDemo
output: true

With Java 7 the class verification was changed.

For class files version 50 (Java 6) the check had a failover if the StackMapTable was missing or wrong (see: jvms-4.10.1).

Run the check with the Foo class version of Java 6.

$ java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)

$ javap -c -v Foo
Classfile /home/suboptimal/playground/Foo.class
Last modified Jun 9, 2017; size 232 bytes
MD5 checksum 5a7ea4a5dd2f6d1bcfddb9ffd720f9c9
public class Foo
minor version: 0
major version: 50 <-- class file Java 6
...

$ javac FooDemo.java
$ java FooDemo
output: true

This failover did not occur anymore for class files version 51 (Java 7).

To create a Foo class version of Java 7 amend the code of FooDump.java.

// cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Foo", null, "java/lang/Object", null);
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "Foo", null, "java/lang/Object", null);

compile and run it

$ javac -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump.java
$ java -cp asm-5.2.jar:asm-util-5.2.jar:. FooDump

check that it's a class version 51

$ java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)

$ javap -c -v Foo
Classfile /home/suboptimal/playground/Foo.class
Last modified Jun 9, 2017; size 232 bytes
MD5 checksum cfd57fb547ac98a1b2808549f5e9e8c1
public class Foo
minor version: 0
major version: 51 <-- class file Java 7
...

$ javac FooDemo.java
$ java FooDemo
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9 in method Foo.bar(Ljava/lang/String;)Z at offset 4

In Java 7 the type check for the StackMapTable attribute can be disabled to step back to the Java 6 failover mechanism using option UseSplitVerifier.

$ java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)

$ java -XX:-UseSplitVerifier FooDemo
output: true

In Java 8 the verification of the StackMapTable attribute became mandatory and the option UseSplitVerifier was removed.

$ java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)

$ javap -c -v Foo
Classfile /home/suboptimal/playground/Foo.class
Last modified Jun 9, 2017; size 232 bytes
MD5 checksum cfd57fb547ac98a1b2808549f5e9e8c1
public class Foo
minor version: 0
major version: 51 <-- class file Java 7
...

$ javac FooDemo.java
$ java FooDemo
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9

$ java -XX:-UseSplitVerifier FooDemo
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option UseSplitVerifier; support was removed in 8.0
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 9

note To use always the initial version of Java 6/7/8 was done by intention to show that the behaviour was there from the beginning.

You might find some suggestions to get it running with Java 8 ...

$ java -noverify FooDemo
output: true

$ java -Xverify:none FooDemo
output: true

note This disables the bytecode verifier. Keep in mind to never disable bytecode verification in a production system.

java.lang.VerifyError: Expecting a stackmap frame

GAE uses Java 1.6, but you've compiled the code with Java 1.7. You need to recompile with Java 1.6. As per the comments, you're using Eclipse; you can set the Java compiler level in Java > Compiler section of project's properties.

Sample Image

How do I overcome the VerifyError:Expecting a stackmap frame for a JDK 7/8 application?

I fixed the issue, after extending ClassWriter class and override the method getCommonSuperClass.

Please check this ASM 5.0.3 With Java 1.8 incorrect maxStack with Java.lang.VerifyError: Operand stack overflow

java.lang.VerifyError: Expecting a stackmap frame at branch target 5

Something generated bytecode. That something is either [A] bugged, and messed up here, producing an invalid class file, or [B] is incredibly old1.

The fix is to, well, fix the code that messed up. If that's not your code, then file a bug with the library. If nobody maintains it anymore, ¯\_(ツ)_/¯, you're out of luck.

The invalid class file is com/karcin/template/persistence/entities/TblAgentPropertyParameters.class.

[1] Technical detail you probably don't need to understand: Well over a decade ago java class file format was changed a little bit to add some hints about stack frames within the class file itself. The verifier is the thing that checks if a class file is 'valid', and that executing the class file cannot lead to what C coders tend to call a 'core dump' - an execution path that would break the security of the system and causes your program to be instantly hardkilled by your OS, or a security issue if the OS fails to detect it. Java promises this cannot happen, and the class verifier is a part of this. The class verifier is helped out by this stack frame registration in the class file: Verifying that this stack frame info is correct, and then verifying that the bytecode only accesses memory that it is allowed to access, is much simpler and faster than verifying that the bytecode only accesses memory that it is allowed to access without this information. Older class files are allowed to not have this registration, in which case the verifier will add it for you (but this takes a lot of time, which is why it's required for more modern class files). Thus, we're really still in buggy territory: Whatever made that class file put a class-file-version in that is high enough that the stack frame notes are required, but did not add them, and thus the verifier is rejecting the class file. Alternatively, because this is 10+ years old news, maybe these days a very modern VM is no longer capable of running very old class files because the 'figure out the stack frame' code has been removed at this point. If this is the case, downgrading back to JDK8 might work, but you really need to address this; you're running code that's 10+ years out of date.



Related Topics



Leave a reply



Submit