JDK-8248552 : C2 crashes with SIGFPE due to division by zero
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 8,11,15,16
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-06-30
  • Updated: 2023-10-11
  • Resolved: 2020-07-27
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 JDK 8
11.0.10-oracleFixed 13.0.8Fixed 15.0.4Fixed 16 b08Fixed 8u371Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
The attached fuzzer test fails with SIGFPE.

To reproduce:
$ java -Xmx1G -Xcomp -Xbatch -XX:-TieredCompilation -XX:CompileOnly=Test Test.java


# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGFPE (0x8) at pc=0x00007fd47090f290, pid=11460, tid=11461
#
# JRE version: Java(TM) SE Runtime Environment (16.0) (slowdebug build 16-internal+0-2020-06-30-0728116.christian...)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (slowdebug 16-internal+0-2020-06-30-0728116.christian..., compiled mode, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# J 90 c2 Test.mainTest([Ljava/lang/String;)V (729 bytes) @ 0x00007fd47090f290 [0x00007fd47090e940+0x0000000000000950]
..........
Command Line: -Xmx1G -Xcomp -Xbatch -XX:-TieredCompilation -XX:CompileOnly=Test --add-modules=ALL-DEFAULT jdk.compiler/com.sun.tools.javac.launcher.Main Test.java
..........
Current thread (0x00007fd474033890):  JavaThread "main" [_thread_in_Java, id=11461, stack(0x00007fd47adcd000,0x00007fd47aece000)]

Stack: [0x00007fd47adcd000,0x00007fd47aece000],  sp=0x00007fd47aecbda0,  free space=1019k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
J 90 c2 Test.mainTest([Ljava/lang/String;)V (729 bytes) @ 0x00007fd47090f290 [0x00007fd47090e940+0x0000000000000950]
J 89 c2 Test.main([Ljava/lang/String;)V (45 bytes) @ 0x00007fd47090aa20 [0x00007fd47090a8a0+0x0000000000000180]
v  ~StubRoutines::call_stub
V  [libjvm.so+0x9df631]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x5fd
V  [libjvm.so+0xea9eec]  os::os_exception_wrapper(void (*)(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*), JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x36
V  [libjvm.so+0x9df030]  JavaCalls::call(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x8e
V  [libjvm.so+0xf4d30f]  invoke(InstanceKlass*, methodHandle const&, Handle, bool, objArrayHandle, BasicType, objArrayHandle, bool, Thread*)+0xcb6
V  [libjvm.so+0xf4d65d]  Reflection::invoke_method(oopDesc*, Handle, objArrayHandle, Thread*)+0x191
V  [libjvm.so+0xaff647]  JVM_InvokeMethod+0x294
C  [libjava.so+0xf414]  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;+113 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+0x9df631]  JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x5fd
V  [libjvm.so+0xea9eec]  os::os_exception_wrapper(void (*)(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*), JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x36
V  [libjvm.so+0x9df030]  JavaCalls::call(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*)+0x8e
V  [libjvm.so+0xa8255c]  jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*)+0x188
V  [libjvm.so+0xa98181]  jni_CallStaticVoidMethod+0x333
C  [libjli.so+0x4a2f]  JavaMain+0xbf7
C  [libjli.so+0xaca5]  ThreadJavaMain+0x27


siginfo: si_signo: 8 (SIGFPE), si_code: 1 (FPE_INTDIV), si_addr: 0x00007fd47090f290
Comments
It seems like https://bugs.openjdk.org/browse/JDK-8229496?focusedCommentId=14293827&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-14293827 is actually this issue.
08-11-2022

Fix request (15u) - will label after testing completed. I'd like to backport this fix to jdk15u for parity with jdk11u. The bug was reproduced with the attached test. After applying the patch the bug was eliminated. The original patch applied cleanly.
09-04-2021

Fix request (13u) - will label after testing completed. I'd like to backport this fix to jdk13u for parity with jdk11u. The bug was reproduced with the attached test. After applying the patch the bug was eliminated. The original patch applied cleanly.
02-04-2021

Fix Request (11u) I would like to backport this to 11u for parity with Oracle 11.0.10-oracle. The original patch applies cleanly.
26-08-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/258505e90ff1 User: chagedorn Date: 2020-07-27 11:05:54 +0000
27-07-2020

Before creating pre/main/post loops, the iv phi has already a narrow type 1..300 set by PhiNode::Value(). However, when creating the pre (and post loop), we actually widen the type of the iv phi of the pre-loop to int>=1 (based on the pre-loop limit which is an Opaque1 node with type int). Roland suggested that we should not do that but instead filter the returned type with the already existing type to not widen it. I think that makes sense. We are already doing that for the other cases in PhiNode::Value() [1][2]. It looks like we just miss it for the special handling of iv phis of trip-counted loops. This also fixes the assertion failure that occurred before with webrev.00. I created a new webrev based on webrev.00 with this change in PhiNode::Value(): http://cr.openjdk.java.net/~chagedorn/8248552/webrev.02/ [1] http://hg.openjdk.java.net/jdk/jdk/file/9ea3344c6445/src/hotspot/share/opto/cfgnode.cpp#l1097 [2] http://hg.openjdk.java.net/jdk/jdk/file/9ea3344c6445/src/hotspot/share/opto/cfgnode.cpp#l1157
16-07-2020

A test in some later tier testing revealed that the assertion code is actually too strong. There can be a Div/Mod node whose zero check was removed but that is then spilt through a non-induction-variable phi whose inputs have zero in their type range (which is fine, this happens in some loop opts after partial peeling was applied earlier). This happened, for example, for a phi which merged two nodes from the original and a cloned loop. I think we just need to remove the additional assertion code. New webrev: http://cr.openjdk.java.net/~chagedorn/8248552/webrev.01/ Failing test with webrev.00: compiler/loopstripmining/DeadNodesInOuterLoopAtLoopCloning.java Additional command line flags to reproduce: -XX:CompileOnly=DeadNodesInOuterLoopAtLoopCloning -Xcomp -XX:+CreateCoredumpOnCrash -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -XX:-TieredCompilation
13-07-2020

http://cr.openjdk.java.net/~chagedorn/8248552/webrev.00/ In the failing testcase, C2 removes a zero check for a division/modulo node n based on the type information of the loop induction variable phi p (always between 1 and 50 and never 0). However, n is later split through p and ends up after the AddNode which updates the induction variable p. In the last iteration j equals 2 and is then updated to 0. The division/modulo node n is now executed before the loop limit check which results in a SIGFPE. The fix bails out of PhaseIdealLoop::split_thru_phi if a division or modulo node has its zero check removed (i.e. control in NULL) and is split through a phi which has an input that could be zero. This should only happen for an induction variable phi of a trip-counted (integer) loop.
10-07-2020