java - 长度超过 65535 字节的 Java 字符串文字的字节码

标签 java jvm-bytecode

我一直在阅读各种文件中的 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 字节 的字符串文字?

最佳答案

既然你说“类文件很旧——版本 46 或 Java 1.2”,确实有可能类文件被破坏了,因为当时的编译器在超出限制时没有拒绝代码。

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

The compiler does not properly enforce certain limits on the number or size of various classfile components. This results in code that appears to compile successfully, but fails at runtime during verification.

These were originally reported as separate bugs, which have now been closed as duplicates of this one. The original bug numbers are included with each item below.

  1. There is a 64k limit on UTF-8 encoded strings. (4071592)

据报道,此错误已在 1.3.1_10 中修复,因此符合时间范围。

请注意,引用的错误 #4071592 指的是在 1.2.0 和更早版本中尝试写入过大的字符串时抛出 UTFDataFormatException,但是 #4303354报告在 1.3.0 中静默生成了无效字符串。因此,如果有问题的类文件是由 javac 生成的,则它必须在版本 1.3.01.3.1_10 之间,并且 -目标 1.2

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

关于java - 长度超过 65535 字节的 Java 字符串文字的字节码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48704270/

相关文章:

java - JVM 规范中 JSR/RET 的状态

java - 检索以字节数组形式存储在类中的字段

java - 计算方法的字节码大小

java - lambda 函数的引用在哪里?

Java Connect4 游戏存在 GUI 错误问题

java - 如何使用 session 工厂从 Java Hibernate 执行 sql 存储过程?

java - 初始化类型由用户指定的 ArrayList

java - p 的交集

java - 如何在非 Activity 类中使用 Activity 方法?当我尝试使用上下文时我的程序崩溃

java - 编译/反汇编Java而不创建常量池?