JDK-8247502 : PhaseStringOpts crashes while optimising effectively dead code
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 11,15,16
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2020-06-12
  • Updated: 2024-11-13
  • Resolved: 2020-07-14
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.8Fixed 15 b32Fixed 16Fixed
Description
The following test failed in the JDK15 CI:

tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest3.java

Here's a snippet from the log file:

Test 30 parameters: tinv=0, tvis=4, inv=0, vis=0, Arepeats=true, BDrepeats=false, ABmix=false, retention: RUNTIME, anno2: TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE, src=src6
Testing classfile: Test30
MCODE: test, RuntimeVisibleTypeAnnotations: 4
  types:METHOD_REFERENCE
  types:METHOD_REFERENCE
  types:METHOD_REFERENCE_TYPE_ARGUMENT
  types:METHOD_REFERENCE_TYPE_ARGUMENT
Pass

Test 31 parameters: tinv=2, tvis=0, inv=2, vis=0, Arepeats=true, BDrepeats=false, ABmix=false, retention: CLASS, anno2: TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIAB
----------stdout:(21/1020)*----------
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ff83d58f1fd, pid=8788, tid=4020
#
# JRE version: Java(TM) SE Runtime Environment (15.0+28) (build 15-ea+28-1379)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (15-ea+28-1379, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# V  [jvm.dll+0x6bf1fd]  PhaseStringOpts::replace_string_concat+0x12bd
#
# Core dump will be written. Default location: T:\\testoutput\\test-support\\jtreg_open_test_langtools_tier1\\scratch\\2\\hs_err_pid8788.mdmp
#
# An error report file with more information is saved as:
# T:\\testoutput\\test-support\\jtreg_open_test_langtools_tier1\\scratch\\2\\hs_err_pid8788.log
#
# Compiler replay data is saved as:
# T:\\testoutput\\test-support\\jtreg_open_test_langtools_tier1\\scratch\\2\\replay_pid8788.log
#
# If you would like to submit a bug report, please visit:
#   https://bugreport.java.com/bugreport/crash.jsp
#
result: Error. Agent communication error: java.net.SocketException: Connection reset; check console log for any additional details


test result: Error. Agent communication error: java.net.SocketException: Connection reset; check console log for any additional details


Here's the crashing thread's stack:

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

Current thread (0x00000240b9513060):  JavaThread "C2 CompilerThread2" daemon [_thread_in_native, id=4020, stack(0x000000b6a1400000,0x000000b6a1500000)]


Current CompileTask:
C2: 265338 18627       4       com.sun.tools.javac.main.Arguments::processArgs (46 bytes)

Stack: [0x000000b6a1400000,0x000000b6a1500000],  sp=0x000000b6a14facc0,  free space=1003k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [jvm.dll+0x6bf1fd]  PhaseStringOpts::replace_string_concat+0x12bd  (stringopts.cpp:1832)
V  [jvm.dll+0x6b96b0]  PhaseStringOpts::PhaseStringOpts+0x4f0  (stringopts.cpp:667)
V  [jvm.dll+0x1f1b56]  Compile::inline_string_calls+0x106  (compile.cpp:1826)
V  [jvm.dll+0x1f14d5]  Compile::inline_incrementally+0x455  (compile.cpp:1956)
V  [jvm.dll+0x1eb0e3]  Compile::Optimize+0x243  (compile.cpp:2048)
V  [jvm.dll+0x1e8e17]  Compile::Compile+0xd17  (compile.cpp:738)
V  [jvm.dll+0x177d97]  C2Compiler::compile_method+0xc7  (c2compiler.cpp:115)
V  [jvm.dll+0x1f8865]  CompileBroker::invoke_compiler_on_method+0x765  (compileBroker.cpp:2223)
V  [jvm.dll+0x1f690c]  CompileBroker::compiler_thread_loop+0x28c  (compileBroker.cpp:1900)
V  [jvm.dll+0x742fad]  JavaThread::run+0x12d  (thread.cpp:1946)
V  [jvm.dll+0x73bdba]  Thread::call_run+0x8a  (thread.cpp:403)
V  [jvm.dll+0x628086]  thread_native_entry+0xd6  (os_windows.cpp:466)
C  [ucrtbase.dll+0x1f4a0]
C  [KERNEL32.DLL+0x84d4]
C  [ntdll.dll+0x6e8b1]


Since this is a Tier1 failure, I'm starting this bug off
as a P2 for initial triage.
Comments
Fix request (13u) - will label after testing completed. I'd like to backport this fix to jdk13u for parity with jdk11u. The original patch applied cleanly.
23-04-2021

Fix Request (11u) This fixes the corner case in C2, which leads to a crash otherwise, and keeps codebases in sync (I see 11.0.10-oracle). Patch applies cleanly to 11u, passes tier{1,2}
31-07-2020

URL: https://hg.openjdk.java.net/jdk/jdk15/rev/91574f2ba3af User: vlivanov Date: 2020-07-14 13:56:37 +0000
14-07-2020

I pushed the fix into jdk/jdk by mistake. Will push it into jdk15 separately.
14-07-2020

The fix got committed to jdk/jdk (JDK 16) http://hg.openjdk.java.net/jdk/jdk/rev/ac9e048a7f09 So now do this to be explicitly committed to jdk/jdk15 also?
14-07-2020

It looks like the bug was introduced by JDK-8214862 which moved the logic which disconnects safepoints after late inlining pass is over. Before the change it was part of PhaseRemoveUseless which is performed right after parsing pass is over (and before initial GVN pass). EDIT: After additional investigation, it turned out the bug is unrelated to JDK-8214862. The problematic part of CFG doesn't go away once safepoints are unlinked from root node, but is kept until loop opts kick in.
09-07-2020

The StringBuilder::append() call with TOP argument is from a dead part of the graph. After initial GVN pass relevant part of CFG degenerated into an infinite loop, but is artificially kept alive by the root node. It goes away once safepoints are disconnected (in Compile::remove_root_to_sfpts_edges()), but it happens after incremental inlining (where string opts are part of).
09-07-2020

I'm able to reproduce this with a product build on Mach 5 approx. once in every 400 runs of langtools tier1. I've added some debug code and theory (3) is correct, the String argument to StringBuilder.append is set to TOP during IGVN, before the String Concat optimization even starts: CallStaticJavaNode 18534 with TOP argument at input 6 virtual jobject java.lang.StringBuilder.append(jobject) Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.so+0xb2006a] Node::remove_dead_region(PhaseGVN*, bool)+0x3ca V [libjvm.so+0x74bbc1] IfNode::Ideal(PhaseGVN*, bool)+0x21 V [libjvm.so+0xb9a572] PhaseIterGVN::transform_old(Node*)+0x92 V [libjvm.so+0xb971a9] PhaseIterGVN::optimize()+0x109 V [libjvm.so+0x52d752] Compile::Optimize()+0x202 V [libjvm.so+0x52f821] Compile::Compile(ciEnv*, ciMethod*, int, bool, bool, bool, DirectiveSet*)+0xd61 V [libjvm.so+0x47ab6c] C2Compiler::compile_method(ciEnv*, ciMethod*, int, DirectiveSet*)+0xfc V [libjvm.so+0x538298] CompileBroker::invoke_compiler_on_method(CompileTask*)+0xd18 V [libjvm.so+0x538ce8] CompileBroker::compiler_thread_loop()+0x4e8 V [libjvm.so+0xcfaa3e] JavaThread::thread_main_inner()+0xde V [libjvm.so+0xcff88d] Thread::call_run()+0xfd V [libjvm.so+0xb502e7] thread_native_entry(Thread*)+0xe7 I.e., it became TOP when removing all users of a dead IfNode. However, the control input remains valid (not-top). Looks like a problem with an IGVN optimization that kills the data path but not the control path to the StringBuilder.append method. Since this is extremely intermittent and only reproduces with a product build, I have not yet been able to identify the root cause. A quick fix would be to simply bail out from String Concat when the argument is TOP but I'm worried that a TOP input might also cause problems at other places.
02-07-2020

Problem: We crash in the string concat C2 optimization because the argument of StringBuffer.append() is TOP. Observations: - Extremely intermittent (happened only 4 times in several months). - Only Strings involved in concat (no integers) - Only happens with incremental inlining. In Compile::inline_incrementally we execute a round of loop opts if the node count is high. Maybe that triggers the issue. Theories: (1) The argument of the StringBuffer constructor call is null and casted to non-null. This would lead to a TOP control and to other arg casts being replaced by TOP as well. -> Would be caught by an assert in fastdebug. (2) Control of final toString call is TOP leading to arg casts being replaced by TOP. -> Would be caught by validate_control_flow(). (3) Arg is top right from the beginning. My current working theory is (3) which would mean that the root cause is a bug that happens earlier and outside of string opts. There is not enough information in the core file to investigate this. I'm currently running more tests to try to reproduce.
23-06-2020

Still not able to reproduce but found an old crash with a 11u fastdebug build: # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007f61cff649d6, pid=13528, tid=13537 # # JRE version: Java(TM) SE Runtime Environment 18.9 (11.0.5+1) (fastdebug build 11.0.5.0.50+1-LTS) # Java VM: Java HotSpot(TM) 64-Bit Server VM 18.9 (fastdebug 11.0.5.0.50+1-LTS, mixed mode, tiered, compressed oops, serial gc, linux-amd64) # Problematic frame: # V [libjvm.so+0x17049d6] PhaseStringOpts::get_constant_coder(GraphKit&, Node*)+0x36 Current CompileTask: C2: 652241 70518 4 com.sun.tck.lib.tgf.MultiplyIterator::shift (42 bytes) Stack: [0x00007f61a85c2000,0x00007f61a86c3000], sp=0x00007f61a86bc980, free space=1002k Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.so+0x17049d6] PhaseStringOpts::get_constant_coder(GraphKit&, Node*)+0x36 V [libjvm.so+0x1706c91] PhaseStringOpts::replace_string_concat(StringConcat*)+0x1271 V [libjvm.so+0x1709207] PhaseStringOpts::PhaseStringOpts(PhaseGVN*, Unique_Node_List*)+0x627 V [libjvm.so+0xa272ac] Compile::inline_string_calls(bool)+0x1dc V [libjvm.so+0xa27a35] Compile::inline_incrementally(PhaseIterGVN&)+0x515 V [libjvm.so+0xa2a321] Compile::Optimize()+0x271 V [libjvm.so+0xa2c104] Compile::Compile(ciEnv*, C2Compiler*, ciMethod*, int, bool, bool, bool, DirectiveSet*)+0xfc4 V [libjvm.so+0x82e05e] C2Compiler::compile_method(ciEnv*, ciMethod*, int, DirectiveSet*)+0xde V [libjvm.so+0xa3935d] CompileBroker::invoke_compiler_on_method(CompileTask*)+0x3fd V [libjvm.so+0xa3a578] CompileBroker::compiler_thread_loop()+0x428 V [libjvm.so+0x17de237] JavaThread::thread_main_inner()+0x2c7 V [libjvm.so+0x17de5b8] JavaThread::run()+0x278 V [libjvm.so+0x14e8130] thread_native_entry(Thread*)+0x100
22-06-2020

Looking at the Linux hs_err, str_type is still in ecx which is 0x0000000000000002 (== Type::Top), i.e. we fail because str is TOP.
15-06-2020

ILW = Crash in C2's string concat optimization, intermittent while compiling a javac method, disable string concat or compilation of affected method = HMM = P2
15-06-2020

0x7ffff6e2e361 <PhaseStringOpts::replace_string_concat(StringConcat*)+9649>: cmp $0x3,%edx 0x7ffff6e2e364 <PhaseStringOpts::replace_string_concat(StringConcat*)+9652>: cmovae %r13,%rax => 0x7ffff6e2e368 <PhaseStringOpts::replace_string_concat(StringConcat*)+9656>: mov 0x30(%rax),%rdi 0x7ffff6e2e36c <PhaseStringOpts::replace_string_concat(StringConcat*)+9660>: lea 0x523a99(%rip),%rax # 0x7ffff7351e0c <_ZN16java_lang_String12coder_offsetE> 0x7ffff6e2e373 <PhaseStringOpts::replace_string_concat(StringConcat*)+9667>: mov (%rax),%esi 0x7ffff6e2e375 <PhaseStringOpts::replace_string_concat(StringConcat*)+9669>: callq 0x7ffff6672720 <ciInstance::field_value_by_offset(int)> 0x7ffff6e2e37a <PhaseStringOpts::replace_string_concat(StringConcat*)+9674>: mov -0x70(%rbp),%rax 0x7ffff6e2e37e <PhaseStringOpts::replace_string_concat(StringConcat*)+9678>: mov %rdx,%rbx 0x7ffff6e2e381 <PhaseStringOpts::replace_string_concat(StringConcat*)+9681>: mov 0x28(%r12),%edx 0x7ffff6e2e386 <PhaseStringOpts::replace_string_concat(StringConcat*)+9686>: mov 0x50(%rax),%rax const TypeOopPtr* str_type = kit.gvn().type(str)->isa_oopptr(); ciInstance* str_instance = str_type->const_oop()->as_instance(); We crash when loading _const_oop from str_type because str_type is NULL.
15-06-2020