【发布时间】:2018-02-09 21:44:14
【问题描述】:
我一直在从各种文件中读取 Java 字节码,以帮助我理解一个项目的 .class 文件,在该项目中我需要与没有源代码和可用文档不足的第 3 方库集成。
为了我自己的乐趣,我通过我的 maven 存储库运行了 Apache BCEL 库,以查看在哪里使用了较少见的类和方法属性(例如类型注释)以及原因。
我偶然发现了一个特定 jar 的问题,该 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) 是长度为 0x480E 的 Utf8 常量 (tag=0x01)。向前移动文件中的该数量确实在该位置有一个字节0x3C。直观地查看文件,我可以看到有问题的常量在位置0x149BD 结束,这使得字符串的实际长度为0x1480E(本质上是位置0x1AC 的前三个字节)。根据 JVM 类文件规范,这当然是不可能的,对于 Utf8 常量,最大长度为 0xFFFF 或 65535。类文件相当旧 - 版本 46 或 Java 1.2。
我仔细研究了规范并尝试了不同的可能实现(更严格和更严格)来尝试解析这个常量,但它要么无法解析它,要么会破坏其他有效 Utf8 常量的读取。
然后我的问题是,我是否遗漏了某些东西,或者是编译器错误,在这种情况下,我的第二个问题是,这首先是如何发生的 - 编译器往往经过相对彻底的检查。最后,Java 编译器通常如何管理长度超过 65535 个字节的字符串文字?
【问题讨论】:
-
编译器似乎无法处理太大的常量:stackoverflow.com/questions/10798769/…
-
授予,鉴于 OP 给出的第一个错误 - 我也相信字符串 literals 仅限于当前编译器中的字符串。但是在这种情况下,它甚至在创建类文件之前。这是一个已经编译的类文件,因此还有其他问题。
标签: java jvm-bytecode