Skip to content

[Native Image] findLeastCommonAncestor: NPE in Crema verifier frame merge, and SubstrateType/RistrettoType confusion in the runtime JIT #14331

Description

@sgammon

Describe the Issue

Two failures in findLeastCommonAncestor, in the two halves of a native image built
with runtime class loading and a runtime JIT (-H:+RuntimeClassLoading,
-H:+GraalJITCompileAtRuntime). Both are internal invariant violations rather than
diagnostics about the application's bytecode, and both occur while computing a
common supertype for a class hierarchy that is partly AOT-analysed and partly loaded
at run time. I believe they are related; they may need separate fixes.

1. Verifier — NullPointerException in InterpreterResolvedObjectType.findLeastCommonAncestor,
reached from ReferenceOperand.mergeWith while merging stack frames at a branch
target. Current, and reproducible in context.

2. Runtime JIT — ClassCastException between the two ResolvedJavaType
implementations.
SubstrateType.findLeastCommonAncestor calls
RistrettoType.isAssignableFrom, which casts its argument to RistrettoType and
receives a SubstrateType. Observed on a slightly earlier build of the same image;
since masked because (1) now aborts earlier.

(2) looks actionable by inspection even without a reproducer: a SubstrateType
reaching a method that unconditionally casts to RistrettoType is a type confusion
between sibling implementations, visible at SubstrateType.java:310 and
RistrettoType.java:120.

GraalVM Version

Image runtime:

java version "25.0.4.1" 2026-08-18 LTS
Java Crema+Ristretto 64-Bit Server VM Oracle GraalVM 25.3.4.1-dev+0.1 (build 25.0.4.1+0-LTS-jvmci-25.3-b21, mixed mode, sharing)
Substrate VM Oracle GraalVM 25.3.4.1-dev+0.1 (build 2026-08-18 LTS, serial gc, compressed references)

Builder: Oracle GraalVM 25.0.4.1+0-LTS, svm 25.0.4.1+0-LTS.

This is a development build of 25.3, not a published release, so I cannot tick the
"tried the latest release" box honestly — if these paths have changed since, please
say and I will re-test.

Operating System and Version

macOS 26.5 (build 25F71, Darwin 25.5.0), arm64.

Run Command

The image is an application launcher; the failing workload is Apache Maven 3.9.16
executing a build inside it. Relevant build-time flags:

-H:+RuntimeClassLoading
-H:+GraalJITCompileAtRuntime
-H:+ParseRuntimeOptions
-H:+UnlockExperimentalVMOptions
--link-at-build-time

Serial GC, compressed references, debug-profile image.

Expected Behavior

Verifying and JIT-compiling ordinary third-party library bytecode succeeds, as it
does on the equivalent HotSpot JDK 25 with the same inputs.

Actual Behavior

1. Verifier NPE

The class under verification is com.puppycrawl.tools.checkstyle.Checker
(Checkstyle 12.3.1). The process prints this and dies:

Fatal error: Unexpected host exception reached the interpreter: java.lang.NullPointerException: null
    at com.oracle.svm.interpreter.metadata.InterpreterResolvedObjectType.findLeastCommonAncestor(InterpreterResolvedObjectType.java:720)
    at com.oracle.svm.interpreter.metadata.InterpreterResolvedObjectType.findLeastCommonAncestor(InterpreterResolvedObjectType.java:73)
    at com.oracle.svm.espresso.shared.verifier.ReferenceOperand.mergeWith(Operand.java:342)
    at com.oracle.svm.espresso.shared.verifier.MethodVerifier.mergeFrames(MethodVerifier.java:2434)
    at com.oracle.svm.espresso.shared.verifier.MethodVerifier.branch(MethodVerifier.java:1106)
    at com.oracle.svm.espresso.shared.verifier.MethodVerifier.verify(MethodVerifier.java:1520)
    at com.oracle.svm.espresso.shared.verifier.MethodVerifier.verifySafe(MethodVerifier.java:1224)
    at com.oracle.svm.espresso.shared.verifier.MethodVerifier.startVerify(MethodVerifier.java:1182)
    at com.oracle.svm.espresso.shared.verifier.MethodVerifier.processQueue(MethodVerifier.java:1002)
    at com.oracle.svm.espresso.shared.verifier.MethodVerifier.verifyReachableCode(MethodVerifier.java:1012)
    at com.oracle.svm.espresso.shared.verifier.Verifier.verify(Verifier.java:51)
    at com.oracle.svm.interpreter.CremaVerifier.verify(CremaVerifier.java:58)
    at com.oracle.svm.interpreter.CremaVerifier.verifyClass(CremaVerifier.java:51)
    at com.puppycrawl.tools.checkstyle.Checker.<init>(Checker.java:144)

Two secondary observations:

  • Since the merge is of two reference operands at a branch target, the null looks
    like a type that could not be resolved during the merge rather than anything
    specific to this class.
  • The message says Fatal error, but it appears again later in the same log, so
    execution continues past a failure the runtime has declared fatal. That may be a
    separate defect in the fatal-error path.

2. Runtime JIT type confusion

Systemic Graal compilation failure detected: 5 of 236 (2%) of compilations failed during last 43 ms
  [max rate set by SystemicCompilationFailureRate is 1%]
Current failure: java.lang.ClassCastException:
  com.oracle.svm.graal.meta.SubstrateType cannot be cast to com.oracle.svm.interpreter.ristretto.meta.RistrettoType
    at com.oracle.svm.interpreter.ristretto.meta.RistrettoType.isAssignableFrom(RistrettoType.java:120)
    at com.oracle.svm.graal.meta.SubstrateType.findLeastCommonAncestor(SubstrateType.java:310)
    at jdk.graal.compiler.core.common.type.AbstractObjectStamp.meetTypes(AbstractObjectStamp.java:316)
    at jdk.graal.compiler.core.common.type.AbstractObjectStamp.meet(AbstractObjectStamp.java:181)
    at jdk.graal.compiler.nodes.type.StampTool.meetOrNull(StampTool.java:69)
    at jdk.graal.compiler.nodes.ValuePhiNode.inferStamp(ValuePhiNode.java:92)
    at jdk.graal.compiler.phases.common.CanonicalizerPhase.tryInferStamp(CanonicalizerPhase.java:888)
    at jdk.graal.compiler.phases.common.CanonicalizerPhase.processNode(CanonicalizerPhase.java:621)
    at jdk.graal.compiler.phases.common.IncrementalCanonicalizerPhase.run(IncrementalCanonicalizerPhase.java:77)
    at jdk.graal.compiler.phases.common.LoweringPhase.lower(LoweringPhase.java:330)

Enough of these tripped the systemic-failure detector that the VM aborted with
exit 134 and no application output.

A third variant tripped the same detector on that build, included only as a data
point since it is a different (missing-feature) case:

Current failure: com.oracle.svm.core.jdk.UnsupportedFeatureError:
  Fast ArrayCopy on byte, uninit false, killing INIT_LOCATION not supported yet.

Steps to Reproduce

I do not have a minimal reproducer, and I would rather say so than send you a
guess.
What I have:

  1. Build an application native image with -H:+RuntimeClassLoading and
    -H:+GraalJITCompileAtRuntime.
  2. Run Apache Maven 3.9.16 inside it against a project whose build invokes
    maven-checkstyle-plugin 3.6.0 with Checkstyle 12.3.1.
  3. The verifier NPE above occurs during the checkstyle phase, deterministically —
    four consecutive runs, identical stack.

Reductions I tried that do not reproduce it, which may narrow where to look:

  • Class.forName("com.puppycrawl.tools.checkstyle.Checker", false, loader) followed
    by getDeclaredConstructors(), with Checkstyle and its dependencies on the class
    path: succeeds.
  • Instantiating it — Class.forName(...).getDeclaredConstructor().newInstance():
    also succeeds.

So verifying Checker.<init> in isolation is fine, and the failure appears to need
the surrounding classloader environment — a frame merge in which one of the operand
types is not resolvable at that moment. That is consistent with the null coming from
a failed type resolution inside the merge rather than from the class's own bytecode.

I am happy to instrument a build and collect more, given a pointer to what would be
most useful — the operand pair being merged at Operand.java:342 seems the obvious
candidate.

Additional Context

Both failures are type-meet operations over a hierarchy the runtime cannot fully
resolve, in the interpreter's metadata and in the JIT's respectively, which is why
they are filed together. If you would prefer them split, say so and I will.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions