用于Java字符串文字的字节码长度超过65535字节

时间:2018-02-09 10:54:08

标签: java jvm-bytecode

我一直在从各种文件中读取Java字节码,以帮助我理解项目的.class文件,我需要与没有源代码和可用文档很差的第三方库集成。

为了我自己的娱乐,我通过我的maven存储库运行Apache BCEL库,以查看使用类型注释等稀有类和方法属性的位置以及原因。

我偶然发现了一个特定jar的问题,该问题无法解码其中一个常量字段 - CONSTANT_Utf8_info。该库是icu4j-2.6.1.jar (com.ibm.icu:icu4j),特别是LocaleElements_zh__PINYIN.class文件。 Apache BCEL失败(我自己尝试在符合JVMS版本8和9的快速字节码阅读器)遇到同样的问题,他们误读了这个常量,然后读取下一个字节,它被评估为一个不正确的常量标记(0x3C / 60)

快速检查一下我是否可以在IDE中使用该类失败(无法解析符号)。使用十六进制编辑器调查实际字节码,表明该偏移处的常量(0x1AC)是一个长度为0x01的Utf8常量(tag = 0x480E)。向前移动文件中的数量确实在该位置有一个字节0x3C。在视觉上查看文件,我可以看到有问题的常量在位置0x149BD结束,这使得字符串0x1480E的实际长度(实际上是位置0x1AC的前三个字节)。根据JVM类文件规范,这当然是不可能的,对于Utf8常量,该规范的最大长度为0xFFFF或65535。类文件很旧 - 版本46或Java 1.2。

我仔细考虑了规范并尝试了不同的可能实现(更少和更严格)来尝试解析这个常量,但是要么无法解析它,要么它会破坏其他有效Utf8常量的读取。

我的问题是,如果我错过了某些内容,或者是编译器错误,在这种情况下,我的第二个问题是如何首先发生这种情况 - 编译器往往会进行相对彻底的检查。最后,Java编译器通常如何管理长度超过65535 bytes 的字符串文字?

1 个答案:

答案 0 :(得分:3)

由于您声明“类文件很旧 - 版本46或Java 1.2”,因此当编译器在超出限制时不会拒绝代码时,确实可能会破坏类文件。

请参阅JDK-4309152 : # Compiler silently generates bytecode that exceeds VM limits

  

编译器未对数字或大小正确实施某些限制   各种类文件组件。这导致代码似乎编译   成功,但在验证期间在运行时失败。

     

这些最初被报告为单独的错误,现已关闭   作为这个的重复。每个都包含原始的错误号   项目如下。

     

...

     
      
  1. UTF-8编码字符串有64k限制。 (4071592)
  2.   

报告此错误已修复为1.3.1_10,因此符合时间范围。

请注意,引用的错误#4071592是指在UTFDataFormatException及更早版本中尝试编写过大字符串时抛出1.2.0,但#4303354报告在1.3.0中无提示生成无效字符串{1}}。因此,如果有问题的类文件是由javac生成的,那么它必须介于版本1.3.01.3.1_10之间-target 1.2

自修复以来,编译器的标准行为是在某个构造超出类文件/ JVM限制时生成编译器错误。