Graal: native-image NPEs in IfNode.prepareForSwap() at com.github.ajalt.clikt.core.CliktCommand.main(List)

Created on 11 Aug 2018  路  4Comments  路  Source: oracle/graal

Repro case: https://github.com/mikaelhg/graal-aot-clikt-repro

Including a particular library, clikt-1.3.0.jar, in a native-image compile results in a NPE in Graal code.

native-image bug.ReproKt --verbose -H:ReflectionConfigurationFiles=reflection.json -H:IncludeResources=.* -H:+ReportUnsupportedElementsAtRuntime -J-Dgraal.InlineDuringParsingMaxDepth=10 -cp build/classes/kotlin/main/:build/resources/main/:/home/mikael/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.2.60/kotlin-stdlib-jdk8-1.2.60.jar:/home/mikael/.m2/repository/org/jetbrains/kotlin/kotlin-reflect/1.2.60/kotlin-reflect-1.2.60.jar:/home/mikael/.gradle/caches/modules-2/files-2.1/com.github.ajalt/clikt/1.3.0/eef12567763b8f1fa4f3096b7febfcd74842831f/clikt-1.3.0.jar:/home/mikael/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.2.60/kotlin-stdlib-jdk7-1.2.60.jar:/home/mikael/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.2.60/kotlin-stdlib-1.2.60.jar:/home/mikael/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.2.60/kotlin-stdlib-common-1.2.60.jar:/home/mikael/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar

       (cap):     695.67 ms
       setup:   1,256.57 ms
  (typeflow):   6,357.65 ms
   (objects):   5,444.75 ms
  (features):      66.51 ms
    analysis:  12,039.13 ms
    universe:     475.55 ms
     (parse):     386.07 ms
     compile:     394.36 ms
fatal error: org.graalvm.compiler.debug.GraalError: java.lang.NullPointerException
        at method: void com.github.ajalt.clikt.core.CliktCommand.main(List)
        at com.oracle.svm.hosted.code.CompileQueue.defaultParseFunction(CompileQueue.java:747)
        at com.oracle.svm.hosted.code.CompileQueue.doParse(CompileQueue.java:649)
        at com.oracle.svm.hosted.code.CompileQueue$ParseTask.run(CompileQueue.java:297)
        at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:174)
        at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
        at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
        at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
        at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
        at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.NullPointerException
        at org.graalvm.compiler.nodes.IfNode.prepareForSwap(IfNode.java:666)
        at org.graalvm.compiler.nodes.IfNode.simplify(IfNode.java:304)
        at org.graalvm.compiler.phases.common.CanonicalizerPhase$Instance.tryCanonicalize(CanonicalizerPhase.java:350)
        at org.graalvm.compiler.phases.common.CanonicalizerPhase$Instance.processNode(CanonicalizerPhase.java:262)
        at org.graalvm.compiler.phases.common.CanonicalizerPhase$Instance.processWorkSet(CanonicalizerPhase.java:241)
        at org.graalvm.compiler.phases.common.CanonicalizerPhase$Instance.run(CanonicalizerPhase.java:211)
        at org.graalvm.compiler.phases.common.CanonicalizerPhase.run(CanonicalizerPhase.java:125)
        at org.graalvm.compiler.phases.common.CanonicalizerPhase.run(CanonicalizerPhase.java:66)
        at org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:197)
        at org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:139)
        at com.oracle.svm.hosted.code.CompileQueue.defaultParseFunction(CompileQueue.java:718)
        ... 8 more
Error: Processing image build request failed
native-image

Most helpful comment

All 4 comments

hot potato

We had some lengthy internal discussion on how exactly to fix this and changed course in the process from a patch I came up with to a smaller, better patch by @christianwimmer :

diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java
index 8b0b7433d00..ac9edbfc13f 100644
--- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java
+++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java
@@ -61,7 +61,7 @@ import jdk.vm.ci.meta.TriState;
 public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
     public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class);

-    private ObjectStamp checkedStamp;
+    private final ObjectStamp checkedStamp;

     private JavaTypeProfile profile;
     @OptionalInput(Anchor) protected AnchoringNode anchor;
@@ -77,6 +77,7 @@ public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtu
         this.anchor = anchor;
         assert (profile == null) || (anchor != null) : "profiles must be anchored";
         assert checkedStamp != null;
+        assert type() != null;
     }

     public static LogicNode createAllowNull(TypeReference type, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) {
@@ -217,11 +218,6 @@ public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtu
         return checkedStamp;
     }

-    public void strengthenCheckedStamp(ObjectStamp newCheckedStamp) {
-        assert this.checkedStamp.join(newCheckedStamp).equals(newCheckedStamp) : "stamp can only improve";
-        this.checkedStamp = newCheckedStamp;
-    }
-
     @Override
     public TriState implies(boolean thisNegated, LogicNode other) {
         if (other instanceof InstanceOfNode) {
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/StrengthenStampsPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/StrengthenStampsPhase.java
index 5098ab6532e..1f80df51c66 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/StrengthenStampsPhase.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/StrengthenStampsPhase.java
@@ -104,7 +104,7 @@ public class StrengthenStampsPhase extends Phase {
                 InstanceOfNode node = (InstanceOfNode) n;
                 ObjectStamp newStamp = (ObjectStamp) strengthen(node.getCheckedStamp());
                 if (newStamp != null) {
-                    node.strengthenCheckedStamp(newStamp);
+                    node.replaceAndDelete(graph.addOrUniqueWithInputs(InstanceOfNode.createHelper(newStamp, node.getValue(), node.profile(), node.getAnchor())));
                 }

             } else if (n instanceof PiNode) {

It should land on github in the next 24 hours. Your reproducer was very helpful and I've confirmed that it is fixed by the pending change.

Verified with 1.0.0 RC6.

Was this page helpful?
0 / 5 - 0 ratings