java - 如何克服 JDK 7/8 应用程序的 "VerifyError:Expecting a stackmap frame"?

标签 java jvm java-bytecode-asm

我在 Tomcat 8 和 JDK 8 中使用 ASM 5.0.3 字节码修改库。

我的目的是将字节码成功地注入(inject)到所有的类中。但是,我遇到了以下错误:

java.lang.VerifyError: Expecting a stackmap frame at branch target 18
Exception Details:
  Location:
    com/sun/crypto/provider/SunJCE.getInstance()Lcom/sun/crypto/provider/SunJCE; @0: getstatic
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0x0000000: b200 0bc7 000b bb00 3659 b700 0cb0 b200
    0x0000010: 0bb0 bf                                
  Exception Handler Table:
    bci [0, 18] => handler: 18
  Stackmap Table:
    append_frame(@14,Integer)

            at java.lang.Class.getDeclaredConstructors0(Native Method)
            at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
            at java.lang.Class.getConstructor0(Unknown Source)
            at java.lang.Class.newInstance(Unknown Source)
            at sun.security.jca.ProviderConfig$2.run(Unknown Source)
            at sun.security.jca.ProviderConfig$2.run(Unknown Source)
           ......Some more uninteresting lines in the stack trace.......
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at java.lang.reflect.Method.invoke(Unknown Source)
            at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:310)
            at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:484)

为了调用 ASM 的方法,我使用的代码的关键部分如下:

ClassWriter classWriter = new  ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);

classReader.accept(myClassVisitor, ClassReader.EXPAND_FRAMES);

以上代码与 JDK 6 应用程序的字节码修改完美结合。该错误仅针对 JDK 7 和 JDK 8 应用程序显示。

各种博客帖子和 stackoverflow 帖子都指向使用 -XX:-UseSplitVerifier 或 -noverify 标志。然而,这似乎是一个短期的解决方法,特别是考虑到 -XX:-UseSplitVerifier 标志在 JDK 8 中已被弃用。我想实现一个永久的解决方案,而不是依赖一个最终在未来的 Java 版本中不受支持的标志。

提前谢谢你。

编辑:引用 Adam 关于使用 COMPUTE_FRAMES 而不是 COMPUTE_MAXS 的善意建议,此链接 ASM - java.lang.VerifyError: Operand stack overflow Exception使用 COMPUTE_FRAMES 总结了到目前为止的错误。目前,我无法使用 COMPUTE_MAXSCOMPUTE_FRAMES 在 JDK 7/8 上取得进展。

最佳答案

使用 ClassWriter#COMPUTE_FRAMES要重新计算的堆栈映射帧的标志。字节码 validator 使用类型检查器(堆栈映射)from JDK 7 on ,所以这就是您的代码在 JDK 6 上运行的原因。

请注意(来自 COMPUTE_FRAMES JavaDoc):

computeFrames implies computeMaxs

关于java - 如何克服 JDK 7/8 应用程序的 "VerifyError:Expecting a stackmap frame"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34506965/

相关文章:

java - Java Web 服务的性能

java - 两个 JFrames 同时运行

java - @Autowiring 在现场级别不起作用

java - 需要在 for 循环中将变量再次初始化为零

java - ASM 转换以查找具体的类类型

使用 ASM 的 Java 字节码检测,MethodVisitor 为 null

java - 如何从我在运行时使用 ASM 动态创建的 Java 类中获取和使用类类型?

elasticsearch - 为什么 Elasticsearch Cluster JVM 内存压力不断增加?

java - promise 堆与最大堆

java - JVM 在何处保存有关引用和对象类型的信息