java.lang.VerifyError:在分支目标处需要一个堆栈图帧

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26733946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 10:30:51  来源:igfitidea点击:

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

javamaventomcatantbuild-process

提问by Suresh Atta

Successfully compiled the project and build as well with Maven. This is my first maven project. But I have no idea why I'm getting the below error.

成功编译项目并使用 Maven 构建。这是我的第一个 Maven 项目。但我不知道为什么会出现以下错误。

Deployeed the war on tomcat and hit my url and the below error shown in my browser.

在 tomcat 上部署War并点击我的网址,并在我的浏览器中显示以下错误。

java.lang.VerifyError: Expecting a stackmap frame at branch target 72
Exception Details:
  Location:
    com/ebetinc/frontend/presentation/components/Login.isToteAvailable(Ljava/lang/String;Lcom/ebetinc/frontend/dao/DatabaseDao;)Z @46: lookupswitch
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0000000: 043d 2bb9 03a4 0100 4e2a c601 1c13 03a6
    0000010: 2ab8 03aa 9900 0803 3da7 010d 2db8 03ad
    0000020: 9900 692a 3a04 0236 0519 04b6 03b1 ab00
    0000030: 0000 003a 0000 0002 0000 0626 0000 002c
    0000040: 0000 0644 0000 001a 0019 0413 03b3 b603
    0000050: b599 0017 0336 05a7 0011 1904 1303 b7b6
    0000060: 03b5 9900 0604 3605 1505 ab00 0000 001c
    0000070: 0000 0002 0000 0000 0000 001a 0000 0001
    0000080: 0000 001a 033d a700 a02d b803 ba99 0099
    0000090: 2a3a 0402 3605 1904 b603 b1ab 0000 006a
    00000a0: 0000 0004 0000 af34 0000 0029 0000 af4c
    00000b0: 0000 003a 0000 af4d 0000 004b 0015 51cb
    00000c0: 0000 005c 1904 1303 bcb6 03b5 9900 3903
    00000d0: 3605 a700 3319 0413 03be b603 b599 0028
    00000e0: 0436 05a7 0022 1904 1303 c0b6 03b5 9900
    00000f0: 1705 3605 a700 1119 0413 03c2 b603 b599
    0000100: 0006 0636 0515 05aa 0000 001f 0000 0000
    0000110: 0000 0003 0000 001d 0000 001d 0000 001d
    0000120: 0000 001d 033d 1cac                    
  Stackmap Table:
    append_frame(@28,Integer,Object[#931])
    append_frame(@73,Object[#200],Integer)
    same_frame(@90)
    same_frame(@104)
    same_frame(@132)
    chop_frame(@134,2)
    same_frame(@137)
    append_frame(@196,Object[#200],Integer)
    same_frame(@213)
    same_frame(@230)
    same_frame(@247)
    same_frame(@261)
    same_frame(@292)
    chop_frame(@294,2)

Can anyone throw some inputs ? Thanks for any help.

任何人都可以抛出一些输入吗?谢谢你的帮助。

Configuration:

配置:

Java 1.7
Maven 3+

回答by SubOptimal

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)

您好,这与您的应用程序中的某些字节码有关。(请参阅有关 Java 7 兼容性更改的说明http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#incompatibilities,在下面查看 JSR 202 的一些行)

You can either

你可以

  • recompile all sources with JDK 7
  • or in case you have no access to the source
    • use javawith paramter -XX:-UseSplitVerifier
    • or switch to Java 6 if you face promblems using the switch
  • 使用 JDK 7 重新编译所有源代码
  • 或者如果您无法访问源
    • java与参数一起使用-XX:-UseSplitVerifier
    • 或者如果您在使用 switch 时遇到问题,请切换到 Java 6

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

编辑即使答案已经有点旧了。由于当前案例,我添加了一些更详细的解释。

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

StackMapTable类文件中的属性是在 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.classwithout the StackMatTableattribute.

以下创建Foo.class没有该StackMatTable属性的文件。

FooDump.java

食物转储.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 StackMapTableattribute is not in the file

检查该StackMapTable属性是否不在文件中

$ 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

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.

在 Java 7 中,类验证发生了变化。

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

对于版本 50 (Java 6) 的类文件,如果StackMapTable缺少或错误,检查会进行故障转移(请参阅:jvms-4.10.1)。

Run the check with the Fooclass version of Java 6.

使用FooJava 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).

类文件版本 51 (Java 7) 不再发生这种故障转移。

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

要创建FooJava 7的类版本,请修改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

检查它是否是类版本 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 StackMapTableattribute can be disabled to step back to the Java 6 failover mechanism using option UseSplitVerifier.

在 Java 7 中,StackMapTable可以使用选项UseSplitVerifier禁用对属性的类型检查以退回到 Java 6 故障转移机制。

$ 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 StackMapTableattribute became mandatory and the option UseSplitVerifierwas removed.

在 Java 8 中,StackMapTable属性的验证成为强制性的,UseSplitVerifier并删除了该选项。

$ 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

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

注意始终使用 Java 6/7/8 的初始版本是为了表明行为从一开始就存在。

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

您可能会发现一些建议使其与 Java 8 一起运行......

$ java -noverify FooDemo
output: true

$ java -Xverify:none FooDemo
output: true

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

注意这会禁用字节码验证器。请记住永远不要在生产系统中禁用字节码验证

回答by LucasNz

I've had the same problem running a Java 1.7 Web Application on a Java 1.7 Weblogic 12C server, while trying to deploy the error occurs:

我在 Java 1.7 Weblogic 12C 服务器上运行 Java 1.7 Web 应用程序时遇到了同样的问题,但在尝试部署时发生了错误:

java.lang.VerifyError: Expecting a stackmap frame at branch target 15
Exception Details: Location: aClassPathWithClassName.$javassist_write_aSpecificField(Ljava/lang/Long;)V
@6: ifnonnull Reason: Expected stackmap frame at this location. 
Bytecode: 0000000: 2ab9 00cc 0100 c700 092a 2bb5 00ce b12a 0000010: 59b9 00d0 0100 2a12 d12a b400 ce2b
b900 0000020: d505 00c0 0081 b500 ceb1

From all classes within the project it happened only with the class being instrumented, aClassPathWithClassName (in the error output above).

在项目中的所有类中,它只发生在被检测的类aClassPathWithClassName(在上面的错误输出中)。

My local solution:

我的本地解决方案:

Locate javassist lib being used by the application on the POM and update it. Here it was 3.10.0.GA, changed to 3.24.1-GA.

在 POM 上找到应用程序正在使用的 javassist 库并更新它。这里是 3.10.0.GA ,更改为3.24.1-GA