我一直在从各种文件中读取Java字节码,以帮助我理解该项目的.class文件,在该项目中,我需要与没有源代码且文档不多的第三方库集成.
出于我自己的娱乐,我在我的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)处的常量是Utf8常量(tag = 0x01),长度为0x480E.向前移动文件中的该数量确实在该位置具有字节0x3C.直观地查看文件,我可以看到所讨论的常量在位置0x149BD处结束,这使字符串的实际长度为0x1480E(实际上是位置0x1AC的前三个字节).根据JVM类文件规范,这当然是不可能的,对于Utf8常量,最大长度为0xFFFF或65535.该类文件非常旧-版本46或Java 1.2.
我仔细研究了该规范,并尝试了其他可能的实现方式(越来越严格)来解析此常量,但它无法解析该常量,或者破坏了对其他有效Utf8常量的读取.
然后我的问题是,我错过了什么,还是编译器错误?在这种情况下,我的第二个问题是,这种情况一开始是怎么发生的-编译器往往会进行相对彻底的检查.最后,Java编译器通常如何管理长度超过65535字节的字符串文字?