我一直在读取各种文件中的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
(是utf8常数(TAG = 0x01
(,其长度为0x480E
。在文件中向前推进该金额确实具有该位置的字节0x3C
。在视觉上查看文件,我可以看到所讨论的常数在位置0x149BD
结束,这使得字符串0x1480E
的实际长度(本质上是位置0x1AC
的前三个字节(。当然,根据JVM ClassFile规范,这当然是不可能的,该规范对于UTF8常数的最大长度为0xFFFF
或65535。ClassFile很旧 - 版本46或Java 1.2。
我已经对规范进行了仔细研究,并尝试了不同的实现(较少和更严格(尝试解析这个常数,但它不能解析它,或者打破了其他有效的UTF8常数的读数。
我的问题是,我错过了一些东西,还是编译器错误,在这种情况下,第二个问题是首先会发生这种情况 - 编译器往往会相对彻底检查。最后,Java编译器通常如何管理长度超过65535 bytes 的字符串文字?
,因为您说" classfile很旧 - 版本46或java 1.2",因此由于当时的编译器不拒绝代码,因此classfile确实有可能仅仅破坏了classfile超过极限时。
参见JDK-4309152:#编译器默默生成超过VM限制的字节码:
编译器无法正确执行数字或大小的某些限制 各种classfile组件。这导致代码似乎是为了编译 成功,但在验证期间运行时失败。
这些最初报告为单独的错误,现在已关闭 作为重复的。每个错误号都包括在内 下面的项目。
…
- UTF-8编码字符串有64K的限制。(4071592(
据报道,此错误已为1.3.1_10
修复,因此适合时间范围。
请注意,引用的错误#4071592是指尝试在1.2.0
及更早的情况下编写过大的字符串时抛出UTFDataFormatException
,但#4303354报告说,1.3.0
中无效的字符串是无效的。因此,如果有问题的类文件是由javac
生成的,则必须使用-target 1.2
版本1.3.0
和1.3.1_10
。
自修复以来,编译器的标准行为是如果某个构造超过类文件/JVM限制,则将编译器错误。