【问题标题】:java.lang.VerifyError: Expecting a stackmap frame at branch targetjava.lang.VerifyError:在分支目标处期望堆栈图帧
【发布时间】:2014-12-31 06:32:12
【问题描述】:

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

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

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)

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

配置:

Java 1.7
Maven 3+

【问题讨论】:

    标签: java maven tomcat ant build-process


    【解决方案1】:

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

    你可以

    • 使用 JDK 7 重新编译所有源代码
    • 或者如果您无权访问源
      • 使用java 和参数-XX:-UseSplitVerifier
      • 如果您在使用开关时遇到问题,请切换到 Java 6

    edit 甚至答案已经有点老了。由于当前的案例,我添加了一些更详细的解释。

    类文件中的 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 */
    }
    

    类验证器没有检查属性是否在类中。

    以下创建不带StackMatTable 属性的文件Foo.class

    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();
        }
    }
    

    编译运行

    $ 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
    

    检查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

    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
    

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

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

    使用 Java 6 的 Foo 类版本运行检查。

    $ 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
    

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

    要创建Java 7 的Foo 类版本,请修改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);
    

    编译运行

    $ 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
    

    检查它是否是类版本 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
    

    在 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
    

    在 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
    

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

    您可能会找到一些建议让它在 Java 8 上运行 ...

    $ java -noverify FooDemo
    output: true
    
    $ java -Xverify:none FooDemo
    output: true
    

    note 这将禁用字节码验证器。请记住never disable bytecode verification in a production system

    【讨论】:

      【解决方案2】:

      我在 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
      

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

      我的本地解决方案:

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

      【讨论】:

        猜你喜欢
        • 2014-10-22
        • 2014-09-19
        • 2021-03-26
        • 1970-01-01
        • 2013-02-13
        • 2017-02-22
        • 1970-01-01
        • 2017-01-07
        相关资源
        最近更新 更多