VerifyError:向后分支/JVM Spec 4.10.2.4中存在未初始化的对象 [英] VerifyError: Uninitialized object exists on backward branch / JVM Spec 4.10.2.4

查看:168
本文介绍了VerifyError:向后分支/JVM Spec 4.10.2.4中存在未初始化的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JVM Spec 4.10 .2.4版本7,最后一段说,

如果未初始化对象的特殊类型与自身以外的特殊类型合并,则有效的指令序列在操作数堆栈上或向后分支目标的局部变量中不得包含未初始化的对象

以下是验证者拒绝的示例-我怀疑应该接受该示例:

public scala.Tuple2<scala.runtime.Null$, scala.runtime.Null$> apply(boolean);
  flags: ACC_PUBLIC
  Code:
    stack=4, locals=2, args_size=2
       0: new           #12                 // class scala/Tuple2
       3: dup           
       4: aconst_null   
       5: iload_1       
       6: ifne          5
       9: aconst_null   
      10: invokespecial #16                 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
      13: areturn       
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      14     0  this   LC;
             0      14     1     x   Z
    StackMapTable: number_of_entries = 1
         frame_type = 255 /* full_frame */
        offset_delta = 5
        locals = [ class C, int ]
        stack = [ uninitialized 0, uninitialized 0, null ]

错误消息抱怨向后跳转ifne 5

java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
  Location:
    C.apply(Z)Lscala/Tuple2; @6: ifne

在跳转目标的堆栈上确实存在一个未初始化的对象;但是,在我看来,未初始化对象的特殊类型"已按照规范要求与自身合并.

我认为只有一个堆栈映射框架,因此不能与其他任何框架合并.

有趣的是,在错误报告).要重现,请使用scala 2.11.1,确保您使用的是JVM> = 1.7,然后运行以下命令(确保将-target:jvm-1.7传递给scala):

localhost:sandbox luc$ scala -target:jvm-1.7
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class C {
     |   def apply(x: Boolean) = new Tuple2(null, {
     |     while (x) { }
     |     null
     |   })
     | }
defined class C

scala> new C
java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
  Location:
    C.apply(Z)Lscala/Tuple2; @6: ifne
  Reason:
    Error exists in the bytecode
  Bytecode:
    0000000: bb00 0959 011b 9aff ff01 b700 0db0
  Stackmap Table:
    full_frame(@5,{Object[#2],Integer},{Uninitialized[#0],Uninitialized[#0],Null})

  ... 32 elided


如上所述- JDK错误报告此处,我希望得到回应在那里.

JDK错误已在 JDK 8u25

JDK错误已在 JDK 8u25 <中修复/p>

The JVM Spec 4.10.2.4 version 7, last paragraph, says

A valid instruction sequence must not have an uninitialized object on the operand stack or in a local variable at the target of a backwards branch if the special type of the uninitialized object is merged with a special type other than itself

Here's an example rejected by the verifier - I suspect that it should be accepted:

public scala.Tuple2<scala.runtime.Null$, scala.runtime.Null$> apply(boolean);
  flags: ACC_PUBLIC
  Code:
    stack=4, locals=2, args_size=2
       0: new           #12                 // class scala/Tuple2
       3: dup           
       4: aconst_null   
       5: iload_1       
       6: ifne          5
       9: aconst_null   
      10: invokespecial #16                 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
      13: areturn       
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      14     0  this   LC;
             0      14     1     x   Z
    StackMapTable: number_of_entries = 1
         frame_type = 255 /* full_frame */
        offset_delta = 5
        locals = [ class C, int ]
        stack = [ uninitialized 0, uninitialized 0, null ]

The error message complains about the backwards jump ifne 5

java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
  Location:
    C.apply(Z)Lscala/Tuple2; @6: ifne

There is indeed an uninitialized object on the stack at the jump target; however, it looks to me that the "special type of the uninitialized object" is merged with itself, just as required by the spec.

I think there is only one stack map frame, so it cannot be merged with anything else.

Interestingly, the restriction on backwards branches was removed in the JVM Spec version 8.

However, the Verifier in Java 8 VM still rejects the example.

Did I misread the JVM spec, or should the example really fail verification? I tried versions 1.7.0_60-b19 and 1.8.0_05-b13.


General Research

The issue shows up in Scala (bugreport). To reproduce, take scala 2.11.1, make sure you're on a JVM >= 1.7 and run the following (be sure to pass -target:jvm-1.7 to scala):

localhost:sandbox luc$ scala -target:jvm-1.7
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class C {
     |   def apply(x: Boolean) = new Tuple2(null, {
     |     while (x) { }
     |     null
     |   })
     | }
defined class C

scala> new C
java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
  Location:
    C.apply(Z)Lscala/Tuple2; @6: ifne
  Reason:
    Error exists in the bytecode
  Bytecode:
    0000000: bb00 0959 011b 9aff ff01 b700 0db0
  Stackmap Table:
    full_frame(@5,{Object[#2],Integer},{Uninitialized[#0],Uninitialized[#0],Null})

  ... 32 elided


As mentioned above - JDK bugreport here, I hope to get a response there.

The JDK bug was fixed in JDK 8u25

解决方案

The JDK bug was fixed in JDK 8u25

这篇关于VerifyError:向后分支/JVM Spec 4.10.2.4中存在未初始化的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆