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 能编过是一件事。

— 感谢阅读 —
广告

一起交流

分享你的思考,让讨论更进一步。