使用java.lang.VerifyError的字节代码验证失败:在分支目标11处期望堆栈映射帧。分支目标11意味着什么?

时间:2015-09-30 06:53:33

标签: java bytecode

当Class加载时,Java 1.8字节代码验证失败.Below是Class SnaControl的构造函数,它无法加载。使用javac 1.6

编译时工作正常
public com.lucent.oms.sna.SnaControl();
descriptor: ()V
flags: ACC_PUBLIC
Code:
  stack=2, locals=1, args_size=1
     0: aload_0
     1: invokespecial #1                  // Method java/lang/Object."<init>":()V
     4: aload_0
     5: aconst_null
     6: putfield      #2                  // Field snaName:Ljava/lang/String;
     9: aload_0
    10: iconst_0
    11: putfield      #3                  // Field snaHealthStatus:Z
    14: aload_0
    15: aconst_null
    16: putfield      #4                  // Field snaPOA:Lorg/omg/PortableServer/POA;
    19: aload_0
    20: aconst_null
    21: putfield      #5                  // Field m_corbaUtil:Lcom/lucent/oms/almapapi/util/CorbaUtil;
    24: aload_0
    25: aconst_null
    26: putfield      #6                  // Field exSnmp:Lcom/lucent/oms/exsnmp/ExSnmpAdapter;
    29: aload_0
    30: putstatic     #7                  // Field snaControlObj:Lcom/lucent/oms/sna/SnaControl;
    33: return
  LineNumberTable:
    line 35: 0
    line 25: 4
    line 26: 9
    line 28: 14
    line 32: 19
    line 33: 24
    line 36: 29
    line 37: 33
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        0      34     0  this   Lcom/lucent/oms/sna/SnaControl;

错误:

Exception in thread "main" java.lang.VerifyError: Expecting a stackmap
frame at branch target 11 Exception Details:   Location:
    com/lucent/oms/sna/SnaControl.<init>()V @4: ifnonnull   Reason:
    Expected stackmap frame at this location.   Bytecode:
    0x0000000: b201 7b59 c700 0757 b801 8503 324c 2ab7
    0x0000010: 0001 2a01 b500 022a 03b5 0003 2a01 b500
    0x0000020: 042a 01b5 0005 2a01 b500 062a b300 072b
    0x0000030: 0304 54b1
   at java.lang.Class.forName0(Native Method)
   at java.lang.Class.forName(Class.java:264)
   at com.lucent.oms.infra.SubsysCtrl.GenericSubsysCtrlHandler.<init>(GenericSubsysCtrlHandler.java:50)
   at com.lucent.oms.infra.SubsysCtrl.SubsysCtrlHandler.<init>(SubsysCtrlHandler.java:36)
   at com.lucent.oms.infra.SubsysCtrl.SimpleSubsystem.initSubsysCtrlHandler(SimpleSubsystem.java:300)
   at com.lucent.oms.infra.SubsysCtrl.SimpleSubsystem.<init>(SimpleSubsystem.java:228)
   at com.lucent.oms.infra.SubsysCtrl.SimpleSubsystem.main(SimpleSubsystem.java:1442)

1 个答案:

答案 0 :(得分:0)

VerifyError将违规字节代码包含为十六进制转储。当我解码它时,我得到:

  0 getstatic   [379]
  3 dup
  4 ifnonnull   @7
  7 pop
  8 invokestatic    [389]
 11 iconst_0
 12 aaload
 13 astore_1

 14 aload_0
 15 invokespecial   [1]
 18 aload_0
 19 aconst_null
 20 putfield    [2]
 23 aload_0
 24 iconst_0
 25 putfield    [3]
 28 aload_0
 29 aconst_null
 30 putfield    [4]
 33 aload_0
 34 aconst_null
 35 putfield    [5]
 38 aload_0
 39 aconst_null
 40 putfield    [6]
 43 aload_0
 44 putstatic   [7]

 47 aload_1
 48 iconst_0
 49 iconst_1
 50 bastore
 51 return

明显不同于您发布的原始代码,但是以可识别的模式。我插入了空行,以便更容易识别新代码中的原始代码。显而易见的是,您的代码已经通过一个工具添加了对方法输入和方法退出的操作进行检测。

问题是您的原始代码是无分支的,而新代码包含从位置4到位置114+7)的条件分支。您应该在VerifyError的消息中识别这些部分:“期望分支目标的堆栈图框 11”和“@4: ifnonnull”。因此,错误不在于您的原始代码,而在于由字节代码检测工具注入的代码。

从类文件v51(Java 7)开始,堆栈映射成为必需的,而对于v50(Java 6),如果发生这些堆栈映射的错误,验证程序将切换到旧的旧版验证程序。这是为了提供更新工具的时间,这些工具无法处理堆栈图,反而导致更多人不了解这种无能为力。

那么实际后果是什么?您必须识别执行无效检测的工具并更新它(希望存在更新)。这可能包括负责资源注入,AOP或分析的框架。通常,这些工具适用于较低级别的字节代码工程库,仅更新该库可能就足够了。好吧,如果您确定了负责的库,您可以搜索“库名+ java8问题”以找到更具体的解决方案。