JDK-8250609 : C2 crash in IfNode::fold_compares
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 9,10,11,15,16
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2020-07-27
  • Updated: 2021-01-13
  • Resolved: 2020-07-29
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 13 JDK 15 JDK 16
11.0.10-oracleFixed 13.0.5Fixed 15Fixed 16 b09Fixed
Related Reports
Duplicate :  
Description
Test case:
public class TestFoldCompares {

    public int test() {
        byte by = -37;
        int result = 1;
        int iArr[] = new int[6];

        for (int i = 0; i < iArr.length; i++) {
            iArr[i] = 0;
        }

        for (int i = 16; i < 308; i++) {
            result *= i;
            if ((result--) <= (++by)) {
                continue;
            }

            for (int j = 3; j < 86; j++) {
                for (int k = 1; k < 2; k++) {
                    result >>= 25;
                }

                for (int k = 1; k < 2; k += 3) {
                    try {
                        iArr[k] = (16986 / result);
                    } catch (ArithmeticException a_e) {
                    }
                    result = k;
                }
            }
        }

        return result;
    }

    public static void main(String[] args) {
        TestFoldCompares obj = new TestFoldCompares();
        for (int i = 0; i < 10; i++) {
            int result = obj.test();
            if (result != 1) {
                throw new RuntimeException("Test failed.");
            }
        }
        System.out.println("Test passed.");
    }

}

$ java TestFoldCompares

---------------  T H R E A D  ---------------

Current thread (0x0000ffff8049dc80):  JavaThread "C2 CompilerThread0" daemon [_thread_in_native, id=123223, stack(0x0000ffff08131000,0x0000ffff08331000)]

Current CompileTask:
C2:   1214   53 % !   4       TestFoldCompares::test @ 77 (140 bytes)

Stack: [0x0000ffff08131000,0x0000ffff08331000],  sp=0x0000ffff0832bb90,  free space=2026k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x41bb6c]  Node::is_Phi() const+0xc
V  [libjvm.so+0x1085be4]  ok_to_convert(Node*, Node*)+0x18
V  [libjvm.so+0x1086024]  SubINode::Ideal(PhaseGVN*, bool)+0x3fc
V  [libjvm.so+0xee1778]  PhaseGVN::apply_ideal(Node*, bool)+0x70
V  [libjvm.so+0xee2ff8]  PhaseIterGVN::transform_old(Node*)+0xf8
V  [libjvm.so+0xee2ef8]  PhaseIterGVN::transform(Node*)+0x8c
V  [libjvm.so+0x99b0cc]  IfNode::fold_compares_helper(ProjNode*, ProjNode*, ProjNode*, PhaseIterGVN*)+0xc14
V  [libjvm.so+0x99c3a0]  IfNode::fold_compares(PhaseIterGVN*)+0x17c
V  [libjvm.so+0x99cb74]  IfNode::Ideal(PhaseGVN*, bool)+0xb4
V  [libjvm.so+0xee1778]  PhaseGVN::apply_ideal(Node*, bool)+0x70
V  [libjvm.so+0xee2ff8]  PhaseIterGVN::transform_old(Node*)+0xf8
V  [libjvm.so+0xee2dac]  PhaseIterGVN::optimize()+0x150
V  [libjvm.so+0x6b7f1c]  Compile::Optimize()+0x930
V  [libjvm.so+0x6b1a64]  Compile::Compile(ciEnv*, ciMethod*, int, bool, bool, bool, bool, DirectiveSet*)+0xc6c
V  [libjvm.so+0x5a31c4]  C2Compiler::compile_method(ciEnv*, ciMethod*, int, bool, DirectiveSet*)+0x158
V  [libjvm.so+0x6cc678]  CompileBroker::invoke_compiler_on_method(CompileTask*)+0x784
V  [libjvm.so+0x6cb438]  CompileBroker::compiler_thread_loop()+0x378
V  [libjvm.so+0x1107334]  compiler_thread_entry(JavaThread*, Thread*)+0x84
V  [libjvm.so+0x1102554]  JavaThread::thread_main_inner()+0x174
V  [libjvm.so+0x11023cc]  JavaThread::run()+0x1a0
V  [libjvm.so+0x10fe2e4]  Thread::call_run()+0x19c
V  [libjvm.so+0xe7e668]  thread_native_entry(Thread*)+0x1e4
C  [libpthread.so.0+0x78bc]  start_thread+0x19c

For the following logic in IfNode::fold_compares_helper:
 995   if (lo && hi) {
 996     // Merge the two compares into a single unsigned compare by building (CmpU (n - lo) (hi - lo))
 997     Node* adjusted_val = igvn->transform(new SubINode(n,  lo));
 998     if (adjusted_lim == NULL) {
 999       adjusted_lim = igvn->transform(new SubINode(hi, lo));
1000     }

At line 997, we have:
(gdb) p lo->dump()
 641    AddI    === _  513  92  [[]]
$1 = void

After the transformation at line 997, we have
(gdb) p lo->dump()
 641    AddI    === _ _ _  [[]]   [34200641]
$3 = void

This node was used at line 999, which triggers the crash.

Proposed fix:
diff -r 14d51ff49d6e src/hotspot/share/opto/ifnode.cpp
--- a/src/hotspot/share/opto/ifnode.cpp Sat Jul 25 16:40:10 2020 +0800
+++ b/src/hotspot/share/opto/ifnode.cpp Mon Jul 27 10:13:12 2020 +0800
@@ -1408,7 +1408,10 @@
   if (in(0) == NULL) return NULL;     // Dead loop?

   PhaseIterGVN* igvn = phase->is_IterGVN();
+  bool saved_delay_transform = igvn->delay_transform();
+  igvn->set_delay_transform(true);
   Node* result = fold_compares(igvn);
+  igvn->set_delay_transform(saved_delay_transform);
   if (result != NULL) {
     return result;
   }
Comments
Test passed in jdk16 ATR.
13-01-2021

Fix request [13u] This fix is applicable to 13u as well. Testing is in progress, label will be set on success.
27-08-2020

Fix Request [11u] This is a C2 bug which causes JVM crash which is always reproducible with JDK11. The fix for C2 is defensive or non-intrusive and will not affect C2 code generation. The newly added test can well ensure the coverage of the fix. Patch applies cleanly to jdk11u-dev. Tier1-3 tested on aarch64-linux-gnu & x86_64-linux-gnu. Newly added test case fail without the fix and pass otherwise.
30-07-2020

Fix request approved for JDK 15.
29-07-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/c4e1b7680506 User: fyang Date: 2020-07-29 16:26:42 +0000
29-07-2020

Fix Request This is a C2 bug which causes JVM crash which is always reproducible with JDK15. The fix for C2 is defensive or non-intrusive and will not affect C2 code generation. The newly added test can well ensure the coverage of the fix. Review thread: https://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2020-July/039207.html Approved webrev: http://cr.openjdk.java.net/~fyang/8250609/webrev.01/ Approved by: Vladimir Kozlov
29-07-2020