JDK-8257822 : C2 crashes with SIGFPE due to a division that floats above its zero check
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 11,12,13,15,16,17
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-12-07
  • Updated: 2022-06-07
  • Resolved: 2020-12-15
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 16 JDK 17
11.0.12-oracleFixed 16 b29Fixed 17Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
The attached fuzzer test fails with SIGFPE:

To reproduce:
$ java -Xcomp -XX:-TieredCompilation -XX:CompileOnly=Test -XX:+StressGCM Test.java

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGFPE (0x8) at pc=0x00007f601d1488d6, pid=4008, tid=4009
#
# JRE version: Java(TM) SE Runtime Environment (16.0) (slowdebug build 16-internal+0-2020-12-03-1109234.christian...)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (slowdebug 16-internal+0-2020-12-03-1109234.christian..., compiled mode, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# J 116 c2 Test.mainTest([Ljava/lang/String;)V (606 bytes) @ 0x00007f601d1488d6 [0x00007f601d148420+0x00000000000004b6]
...........
Command Line: -Xcomp -XX:-TieredCompilation -XX:CompileOnly=Test -XX:+StressGCM --add-modules=ALL-DEFAULT jdk.compiler/com.sun.tools.javac.launcher.Main Test.java
...........
Current thread (0x00007f60200284e0):  JavaThread "main" [_thread_in_Java, id=4009, stack(0x00007f6029253000,0x00007f6029354000)]

Stack: [0x00007f6029253000,0x00007f6029354000],  sp=0x00007f6029351d80,  free space=1019k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
J 116 c2 Test.mainTest([Ljava/lang/String;)V (606 bytes) @ 0x00007f601d1488d6 [0x00007f601d148420+0x00000000000004b6]
J 85 c2 Test.main([Ljava/lang/String;)V (45 bytes) @ 0x00007f601d124be0 [0x00007f601d124b60+0x0000000000000080]
v  ~StubRoutines::call_stub
V  [libjvm.so+0xab587b]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x59d
V  [libjvm.so+0xfa888e]  os::os_exception_wrapper(void (*)(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*), JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x36
V  [libjvm.so+0xab52da]  JavaCalls::call(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x8e
V  [libjvm.so+0x104f70e]  invoke(InstanceKlass*, methodHandle const&, Handle, bool, objArrayHandle, BasicType, objArrayHandle, bool, Thread*)+0xcbe
V  [libjvm.so+0x104fa61]  Reflection::invoke_method(oopDesc*, Handle, objArrayHandle, Thread*)+0x191
V  [libjvm.so+0xbdd7d6]  JVM_InvokeMethod+0x29f
C  [libjava.so+0x10737]  Java_jdk_internal_reflect_NativeMethodAccessorImpl_invoke0+0x43
j  jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+0 java.base
j  jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+146 java.base
j  jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+6 java.base
j  java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+59 java.base
j  com.sun.tools.javac.launcher.Main.execute(Ljava/lang/String;[Ljava/lang/String;Lcom/sun/tools/javac/launcher/Main$Context;)V+128 jdk.compiler
j  com.sun.tools.javac.launcher.Main.run([Ljava/lang/String;[Ljava/lang/String;)V+54 jdk.compiler
j  com.sun.tools.javac.launcher.Main.main([Ljava/lang/String;)V+14 jdk.compiler
v  ~StubRoutines::call_stub
V  [libjvm.so+0xab587b]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x59d
V  [libjvm.so+0xfa888e]  os::os_exception_wrapper(void (*)(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*), JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x36
V  [libjvm.so+0xab52da]  JavaCalls::call(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x8e
V  [libjvm.so+0xb5ee62]  jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*)+0x188
V  [libjvm.so+0xb74ab5]  jni_CallStaticVoidMethod+0x333
C  [libjli.so+0x4d6d]  JavaMain+0xbf7
C  [libjli.so+0xaf77]  ThreadJavaMain+0x27


siginfo: si_signo: 8 (SIGFPE), si_code: 1 (FPE_INTDIV), si_addr: 0x00007f601d1488d6
Comments
Fix Request (11u) Should get backported for parity with 11.0.12-oracle (together with the follow-up fixes). This one applies almost cleanly. Review thread: http://mail.openjdk.java.net/pipermail/jdk-updates-dev/2021-March/005393.html
19-03-2021

Changeset: ce36aeaa Author: Christian Hagedorn <chagedorn@openjdk.org> Date: 2020-12-15 15:14:34 +0000 URL: https://git.openjdk.java.net/jdk16/commit/ce36aeaa
15-12-2020

JMH Benchmark results from JDK-8242108 (test/micro/org/openjdk/bench/java/text/DefFormatterBench.java): Base === Benchmark (value) Mode Cnt Score Error Units DefFormatterBench.testDefNumberFormatter 1.23 thrpt 5 2613.017 ? 23.079 ops/ms DefFormatterBench.testDefNumberFormatter 1.49 thrpt 5 2608.521 ? 12.501 ops/ms DefFormatterBench.testDefNumberFormatter 1.80 thrpt 5 2702.747 ? 13.617 ops/ms DefFormatterBench.testDefNumberFormatter 1.7 thrpt 5 2704.739 ? 10.801 ops/ms DefFormatterBench.testDefNumberFormatter 0.0 thrpt 5 3004.561 ? 48.565 ops/ms DefFormatterBench.testDefNumberFormatter -1.49 thrpt 5 2428.521 ? 13.273 ops/ms DefFormatterBench.testDefNumberFormatter -1.50 thrpt 5 2485.056 ? 8.545 ops/ms DefFormatterBench.testDefNumberFormatter 9999.9123 thrpt 5 1855.488 ? 20.135 ops/ms DefFormatterBench.testDefNumberFormatter 1.494 thrpt 5 2469.270 ? 12.324 ops/ms DefFormatterBench.testDefNumberFormatter 1.495 thrpt 5 2458.773 ? 26.828 ops/ms DefFormatterBench.testDefNumberFormatter 1.03 thrpt 5 2611.538 ? 17.118 ops/ms DefFormatterBench.testDefNumberFormatter 25.996 thrpt 5 2233.296 ? 5.277 ops/ms DefFormatterBench.testDefNumberFormatter -25.996 thrpt 5 2078.811 ? 8.886 ops/ms Fix == Benchmark (value) Mode Cnt Score Error Units DefFormatterBench.testDefNumberFormatter 1.23 thrpt 5 2627.609 ? 10.549 ops/ms DefFormatterBench.testDefNumberFormatter 1.49 thrpt 5 2616.200 ? 36.761 ops/ms DefFormatterBench.testDefNumberFormatter 1.80 thrpt 5 2703.199 ? 8.354 ops/ms DefFormatterBench.testDefNumberFormatter 1.7 thrpt 5 2707.708 ? 28.395 ops/ms DefFormatterBench.testDefNumberFormatter 0.0 thrpt 5 3071.235 ? 29.940 ops/ms DefFormatterBench.testDefNumberFormatter -1.49 thrpt 5 2424.642 ? 7.844 ops/ms DefFormatterBench.testDefNumberFormatter -1.50 thrpt 5 2480.584 ? 18.594 ops/ms DefFormatterBench.testDefNumberFormatter 9999.9123 thrpt 5 1851.475 ? 10.832 ops/ms DefFormatterBench.testDefNumberFormatter 1.494 thrpt 5 2482.056 ? 12.004 ops/ms DefFormatterBench.testDefNumberFormatter 1.495 thrpt 5 2450.672 ? 22.663 ops/ms DefFormatterBench.testDefNumberFormatter 1.03 thrpt 5 2607.539 ? 54.347 ops/ms DefFormatterBench.testDefNumberFormatter 25.996 thrpt 5 2234.088 ? 17.963 ops/ms DefFormatterBench.testDefNumberFormatter -25.996 thrpt 5 2078.508 ? 11.534 ops/ms
11-12-2020

Seems to be the same problem is in JDK-8229496 which was pushed in JDK 14. However, it was later backed out in JDK 15 by JDK-8242108 due to a performance regression and because it was assumed that JDK-8241900 fixed the problem. Therefore, it does not reproduce with JDK 14. It was originally thought that loop unswitching is responsible for the problem in JDK-8229496 to arise. But the found fuzzer test of this bug triggers without loop unswitching. Summary of the problem in this bug: - A DivINode is added with its zero check. - The zero check is then split through a region which creates two zero checks Z1 and Z2. - The DivINode, however, is not split and therefore gets a new region node R as control input that merges Z1 and Z2. - Z1 can be immediately be removed because the test is always false. - Z2 can also be removed because there is dominating test Z3 with the same BoolNode (the zero check for the DIvINode). - R is removed and the DivINode's control input is set to an array RangeCheckNode. Up to this point Z3 still dominates the DivINode and everthing is fine. - Loop predicates are added to the outer loop in PhaseIdealLoop::loop_predication_impl_helper() and since the DivINode is control dependent on the RangeCheck, it is also moved out of the loop by PhaseIdealLoop::dominated_by() because depends_only_on_test() is true for Div nodes. - The zero check Z3, however, is still part of the loop and could end up being executed after the DivINode. - Exactly that happens with StressGCM: The integer division is scheduled before the actual zero check Z3, resulting in a SIGFPE crash. Fix attempts and current state: - Current state: PhaseIdealLoop::dominated_by() moves all Div nodes out of the loop which is wrong. - JDK-8229694: Added CastLL nodes to prevent PhaseIdealLoop::dominated_by() from moving out any Div/Mod nodes (CastLL nodes returned false for depends_only_on_test()) which was too conservative and resulted in a preformance regression (JDK-8242108). - JDK-8242108: Backed JDK-8229694 out again, back to current state. An idea to address this problem again is to change PhaseIdealLoop::dominated_by() to move Div/Mod nodes out of a loop if we know that the zero check was removed. This could be achieved by looking at the type of the Div/Mod nodes and check if they contain zero. This is less conservative but not perfect as the zero check could have been removed due to a "!= 0" check but the type cannot reflect this as there is no type "Everything except zero". Another idea is to update the Split If optimization to ensure that a Div/Mod node is still directly control dependent by the zero check. However, I don't think that we are guaranteed that a Div/Mod node has always the zero check as direct control input.
08-12-2020

ILW = Crash with SIGFPE in C2 when run with -XX:+StressGCM, only fails with single Java Fuzzer test and not a recent regression, disable compilation of affected method or run with -XX:-StressGCM = HLM = P3
07-12-2020