JDK-8394468 截至 2026-10-26 仍是 Unresolved(P3,tools/javac)。一句话就能让 javac 崩:(true ? null : "abc").length()。我在 21.0.12.1、27.0.1.0.3 和 28-ea+21-1707 上复现,退出码都是 4,栈顶是 AssertionError: Invalid pool entry。
对调操作数、把条件改成变量、先赋给 String 再调用,都能过编译。Spring Boot 3.5.6 里只要 Controller 写了崩法,mvn compile 就会变成 “An unknown compilation problem occurred”。
官方单子写了什么
JBS 标题是 Compiler Bug "Invalid pool entry",组件 tools / javac,优先级 P3。复现步骤只有一行:
public class JavacBug {
public static void main(String[] args) {
int n = (true ? null : "abc").length();
System.out.println(n);
}
}
报告里写 Last worked in version 11.0.32.1;Affects 列了 17.0.20.1、21.0.12.1、25.0.4.1、26.0.2.1。单子 10-13 创建;10-25 已分配给 Jonghoon Park,并挂出 openjdk/jdk#33555(rfr,尚未合入)。和早前写过的 JDK 27 C2 EncodeISOArray 不同:那次是运行期写坏字符串,这次卡在编译期常量池写入。
本机三套 JDK 的对照
版本串如下:
openjdk version "21.0.12.1" 2026-08-18
OpenJDK Runtime Environment (build 21.0.12.1+1-1-deb13u1-Debian)
openjdk version "27.0.1.0.3" 2026-10-25
OpenJDK Runtime Environment (build 27.0.1.0.3+1-2)
openjdk version "28-ea" 2027-03-23
OpenJDK Runtime Environment (build 28-ea+21-1707)
同一组探针,结果一致:
CaseNullFirst: CRASH exit=4 AssertionError: Invalid pool entry
CaseStrFirst: OK run=[3] // (true ? "abc" : null).length()
CaseFalseNullFirst: OK run=[3] // (false ? null : "abc").length()
CaseVar: OK // (b ? null : "abc").length()
false=3
true->java.lang.NullPointerException: Cannot invoke "String.length()"
CaseAssign: OK run=[s=null] // String s = true ? null : "abc";
也就是说,崩点很窄:条件是编译期常量 true,并且 null 写在真分支,后面立刻做实例方法调用。常量 false 会被折成 "abc",所以能编过。条件是变量时类型按 String 走,能编过;真值运行才会 NPE。
崩栈长什么样
28-ea+21 上直接跑 javac CaseNullFirst.java,原文如下:
An exception has occurred in the compiler (28-ea). Please file a bug against the Java compiler via the Java bug reporting page (https://bugreport.java.com) after checking the Bug Database (https://bugs.java.com) for duplicates. Include your program, the following diagnostic, and the parameters passed to the Java compiler in your report. Thank you.
java.lang.AssertionError: Invalid pool entry
at jdk.compiler/com.sun.tools.javac.code.Type.poolTag(Type.java:129)
at jdk.compiler/com.sun.tools.javac.jvm.PoolWriter$WriteablePoolHelper.writeConstant(PoolWriter.java:381)
at jdk.compiler/com.sun.tools.javac.jvm.PoolWriter$WriteablePoolHelper.writeIfNeeded(PoolWriter.java:372)
at jdk.compiler/com.sun.tools.javac.jvm.PoolWriter.putMember(PoolWriter.java:130)
at jdk.compiler/com.sun.tools.javac.jvm.Code.emitInvokevirtual(Code.java:499)
at jdk.compiler/com.sun.tools.javac.jvm.Items$MemberItem.invoke(Items.java:534)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitApply(Gen.java:2050)
生成 invokevirtual 时要给接收者类型写常量池标签,poolTag 断言失败。21 和 27.0.1.0.3 的栈同形,只是行号略有差别。
落到 Spring Boot 3.5.6
父 POM 用 Spring Boot 3.5.6,一个会崩的 Controller:
@RestController
public class CrashController {
@GetMapping("/crash")
public int crash() {
return (true ? null : "abc").length();
}
}
在 28-ea+21 上 mvn -DskipTests compile 失败。Maven 把 javac 的断言包成:
java.lang.AssertionError: Invalid pool entry
at jdk.compiler/com.sun.tools.javac.code.Type.poolTag(Type.java:129)
...
[ERROR] COMPILATION ERROR :
[ERROR] An unknown compilation problem occurred
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.14.0:compile (default-compile) on project javac-null-ternary-pool: Compilation failure
[ERROR] An unknown compilation problem occurred
去掉这个类后,同工程能干净编过并启动。对照接口实测:
GET /str-first -> 3
GET /false-null-first -> 3
GET /var?b=false -> 3
GET /var?b=true -> 500 Internal Server Error
GET /assign -> -1
/assign 先写成 String s = true ? null : "abc",再判空返回 -1,所以是 -1 而不是编译失败。这和探针里 CaseAssign 能编过是一件事。
一起交流
分享你的思考,让讨论更进一步。