Oracle最新的Java 8更新破坏了您的工具-它是如何发生的?

断裂
如果您最近一直在关注Java世界的消息,那么您可能听说过Oracle发布的最新Java 8构建,Java 8u11(和Java 7u65)引入了错误并破坏了一些流行的第三方工具,例如ZeroTurnaround的JRebel,Javassist,Google的Guice甚至Groovy本身。

JVM产生的错误是漫长而冗长的,但从本质上讲,它们看起来像这样:

Exception in thread "main" java.lang.VerifyError: Bad method call from inside of a branch
Exception Details:
   Location:
   com/takipi/tests/dc/DepthCounter.()V @10: invokespecial
   …

这些错误突然开始出现的原因是由于最新更新中的字节码验证程序比以前的版本更加严格。 与以前的版本不同,它不允许在分支代码中调用超级构造函数。

让我们分解一下。

Java字节码和字节码验证程序

字节码是JVM实际执行的中间语言,并且编写编译的.class文件。 JVM的机器代码(如果需要)。

通过Java,通过Scala,Groovy,Clojure等将所有基于JVM的语言编译成字节码。 JVM不知道也不在乎源语言是什么-它只知道字节码。

我不打算讨论字节码的工作原理 ,因为它是一个主题(或一个或多个帖子),但仅是要了解一下字节码的样子,以这种简单的Java方法为例:

int add(int x, int y) {
   int z = x + y;
   return z;
}

编译后,其字节码如下所示:

ILOAD x
ILOAD y
IADD
ISTORE z
ILOAD z
IRETURN

当JVM将类文件从类路径加载到内存中时,它首先必须确保字节码有效并且代码结构正确。 它基本上检查正在加载的代码是否可以实际执行。 如果字节码正确,则该类已成功加载到内存中; 否则,将引发VerifyError ,就像帖子开头的错误一样。

此过程称为字节码验证,而负责该过程的JVM部分是字节码验证程序。

为什么会破裂?

为了使字节码通过验证,它必须遵守类文件格式规范中定义的一组规则。 由于JVM最初是考虑到Java编程语言而设计的,因此许多规则都是直接从Java规则和约束派生的。

Java语言中这样一个众所周知的约束是,在执行其他任何操作之前,必须在构造函数中首先要做的是调用super(…)this(…) 。 之前的任何一段代码-您的代码都不会编译。 即使您没有显式编写super() ,编译器也会在构造函数的最开始为您隐式地插入它。

字节码验证规则中至少在纸面上存在相同的约束。 但是,事实证明,直到这些最新的JDK更新,此约束才得以完全实施。 这意味着,尽管没有Java编译器会允许您编译此代码:

public static class ClassyClass {
   public ClassyClass() {
      if (checkSomething()) {
         super();
      } else {
         super(getSomething());
      }
   }
}

…等效的字节码将通过验证!

ALOAD this
    INVOKESTATIC checkSomething() : boolean
    IFEQ L2
    INVOKESPECIAL super() : void
    GOTO L2
L1: INVOKESTATIC getSomething() : int
    INVOKESPECIAL super(int) : void
L2: RETURN

您可以在上面的简化字节码中看到,在第一次调用超构造函数( INVOKESPECIAL )之前,既有一个调用( INVOKESTATIC ),也有一个分支( IFEQ —“如果相等”)。

请记住,尽管以上代码不是合法的Java,因此没有Java编译器会生成等效的字节码-还有许多其他可能的工具,例如不遵循Java约束的其他JVM语言的编译器,以及许多其他工具,例如字节码检测库。 在调用super之前执行代码的功能非常有用!

但是,Java 8 update 11带来了更严格的字节码验证程序,该验证程序拒绝在字节码中使用此类构造的类,并导致引发验证错误和JVM崩溃。

一方面,新的验证程序忠于该规范,从而确保我们的JVM免受不良代码的侵害。 另一方面,许多利用字节码检测的工具,例如调试器和Aspect Weavers(AOP),通常都使用上述结构。

怎么解决呢?

字节码验证程序的修复程序已提交 ,但尚未发布。 但是,许多受影响的工具和项目已经发布了固定版本和解决方法。

同时,如果您碰巧遇到这些错误之一,则可以尝试使用-noverify命令行参数启动JVM。 此选项指示JVM在加载类时跳过字节码验证。

翻译自: https://www.javacodegeeks.com/2014/08/oracles-latest-java-8-update-broke-your-tools-how-did-it-happen.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值