JDK-8247743 : Segmentation fault in debug builds due to stack overflow in find_recur with deep graphs
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 11,12,13,14,15,16
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-06-17
  • Updated: 2024-11-13
  • Resolved: 2020-07-22
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 16
16 b07Fixed
Related Reports
Relates :  
Description
The attached test case results in a segmentation fault with a debug build with the following command line:
java -Xcomp -XX:CompileCommand=option,Test::main,uintx,VectorizeDebug,65 -XX:CompileCommand=compileonly,Test::main Test.java

The test was adapted from compiler/loopopts/TestDeepGraphVerifyIterativeGVN.java to also trigger the super word optimization. By additionally specifying the VectorizeDebug option, the code calls SuperWord::print_loop() -> PhaseIdealLoop::dump() -> C->root()->find(k) which then finally calls the recursive method find_recur(). Since the IR contains a lot of nodes in a chain, find_recur() calls itself recursively over and over again - eventually resulting in a stack overflow segmentation fault (similar to JDK-8246203). The suggested fix is the same as in JDK-8246203 to change the recursive algorithm into an iterative one.

Log:
CompileCommand: option Test.main uintx VectorizeDebug = 65
CompileCommand: compileonly Test.main
SuperWord::construct_bb: List of generations:   0:15  1:12  2:11  3:8  4:7  5:4  6:3  7:0 
SuperWord::mark_generations
First generation (15) nodes:
 33821	CountedLoop	===  33821  33170  2871  [[ 33785  33792  33799  33801  33820  33821  33699  33824  33706  38  33633  33166 ]]  {33171:15} inner stride: 8 main of N33821 strip mined !orig=[33716],[33641],[33171],[33161],[1840] !jvms: Test::main @ bci:2349
 33820	Phi	===  33821  33560  1841  [[ 33848  33816  33817  33818  33819  33831  1841  33840  33844 ]]  {809:15}  #int:1..51:www #tripcount !orig=[33719],33645,[809],[8459] !jvms: Test::main @ bci:2349
 33818	ConvI2L	=== _  33820  [[ 33807 ]]  {5680:15}  #long:1..50:www !orig=[33718],[33644],[5680],[3676] !jvms: Test::main @ bci:2349
 33807	LShiftL	=== _  33818  3677  [[ 33804  33806 ]]  {3652:15}  !orig=[33712],[33639],[3652],[2892] !jvms: Test::main @ bci:2349
 33804	AddP	=== _  813  813  33807  [[ 33803 ]]  {2877:15}  !orig=[33709],[33636],[2877] !jvms: Test::main @ bci:2349
 33803	AddP	=== _  813  33804  1859  [[ 33802 ]]  {1848:15}  !orig=33708,33635,1848 !jvms: Test::main @ bci:2349
 33806	AddP	=== _  817  817  33807  [[ 33805 ]]  {1858:15}  !orig=[33711],[33638],[1858] !jvms: Test::main @ bci:2349
 33805	AddP	=== _  817  33806  1859  [[ 33801 ]]  {829:15}  !orig=33710,33637,829 !jvms: Test::main @ bci:2349
 33824	Phi	===  33821  33533  38  [[ 33801  33802 ]]  {828:15}  #memory  Memory: @int[int:>=0]:exact+any *, idx=6; !orig=33722,33640,828,[50861],[50760] !jvms: Test::main @ bci:2353
 33802	LoadI	===  33559  33824  33803  [[ 33801 ]]  {815:15}  @int[int:>=0]:exact+any *, idx=6; #int !orig=33707,33634,815 !jvms: Test::main @ bci:2349
 33801	StoreI	===  33821  33824  33805  33802  [[ 33799  33800 ]]  {38:15}  @int[int:>=0]:exact+any *, idx=6;  Memory: @int[int:>=0]:NotNull:exact+any *, idx=6; !orig=33706,33633,38,33650 !jvms: Test::main @ bci:2349
Last generation (0) nodes:
 33848	ConvI2L	=== _  33820  [[ 33856 ]]  #long:1..46:www
 33856	LShiftL	=== _  33848  3677  [[ 33864  33862 ]] 
 33864	AddP	=== _  817  817  33856  [[ 33710 ]] 
 33862	AddP	=== _  813  813  33856  [[ 33708 ]]  !jvms: Test::main @ bci:2361
 33831	ConvI2L	=== _  33820  [[ 33835 ]]  #long:1..44:www
 33835	LShiftL	=== _  33831  3677  [[ 33839  33837 ]] 
 33839	AddP	=== _  817  817  33835  [[ 33637 ]]  !jvms: Test::main @ bci:2353
 33837	AddP	=== _  813  813  33835  [[ 33635 ]] 
 1841	AddI	=== _  33820  16818  [[ 33550  33164  33820  33172 ]]  {1841:0}  !orig=[33163],... !jvms: Test::main @ bci:123
 33164	CmpI	=== _  1841  33784  [[ 33165 ]]  {33164:0}  !orig=[1853] !jvms: Test::main @ bci:2307
 33165	Bool	=== _  33164  [[ 33166 ]]  {33165:0} [lt] !orig=[819] !jvms: Test::main @ bci:2307
 33840	ConvI2L	=== _  33820  [[ 33852 ]]  #long:1..45:www !jvms: Test::main @ bci:2353
 33852	LShiftL	=== _  33840  3677  [[ 33859  33858 ]] 
 33859	AddP	=== _  817  817  33852  [[ 33703 ]] 
 33858	AddP	=== _  813  813  33852  [[ 33701 ]] 
 33844	ConvI2L	=== _  33820  [[ 33854 ]]  #long:1..43:www
 33854	LShiftL	=== _  33844  3677  [[ 33861  33860 ]] 
 33861	AddP	=== _  817  817  33854  [[ 829 ]]  !jvms: Test::main @ bci:2361
 829	AddP	=== _  817  33861  33865  [[ 38 ]]  {829:0}  !jvms: Test::main @ bci:53
 33860	AddP	=== _  813  813  33854  [[ 1848 ]]  !jvms: Test::main @ bci:2361
 1848	AddP	=== _  813  33860  33865  [[ 815 ]]  {1848:0}  !jvms: Test::main @ bci:123
 815	LoadI	===  33559  33633  1848  [[ 38 ]]  {815:0}  @int[int:>=0]:exact+any *, idx=6; #int !jvms: Test::main @ bci:53
 38	StoreI	===  33821  33633  829  815  [[ 33824  1851  33552 ]]  {38:0}  @int[int:>=0]:exact+any *, idx=6;  Memory: @int[int:>=0]:NotNull:exact+any *, idx=6; !orig=33650 !jvms: Test::main @ bci:2343
 
SuperWord::List of generations: 0:15 1:12 2:11 3:8 4:7 5:4 6:3 7:0  
SuperWord::hoist_loads_in_graph: total number _mem_slice_head.length() = 1
SuperWord::hoist_loads_in_graph: processing phi 33824  = _mem_slice_head.at(0);
SuperWord::hoist_loads_in_graph: will try to hoist load ld2->_idx=33800, cloned from 815 (ld->_idx=33802)
SuperWord::hoist_loads_in_graph: will try to hoist load ld2->_idx=33795, cloned from 815 (ld->_idx=33802)
SuperWord::hoist_loads_in_graph: will try to hoist load ld2->_idx=33788, cloned from 815 (ld->_idx=33802)
SuperWord::hoist_loads_in_graph: will try to hoist load ld2->_idx=33707, cloned from 815 (ld->_idx=33802)
SuperWord::hoist_loads_in_graph: will try to hoist load ld2->_idx=33700, cloned from 815 (ld->_idx=33802)
SuperWord::hoist_loads_in_graph: will try to hoist load ld2->_idx=33634, cloned from 815 (ld->_idx=33802)
SuperWord::hoist_loads_in_graph: will try to hoist load ld2->_idx=815, cloned from 815 (ld->_idx=33802)
SuperWord::first_node: 33802 is the first iteration node for 33800 (_clone_map.idx(nnn->_idx) = 815)
SuperWord::hoist_loads_in_graph replacing MemNode::Memory(1) edge in 33800 with one from 33824
SuperWord::first_node: 33802 is the first iteration node for 33795 (_clone_map.idx(nnn->_idx) = 815)
SuperWord::hoist_loads_in_graph replacing MemNode::Memory(1) edge in 33795 with one from 33824
SuperWord::first_node: 33802 is the first iteration node for 33788 (_clone_map.idx(nnn->_idx) = 815)
SuperWord::hoist_loads_in_graph replacing MemNode::Memory(1) edge in 33788 with one from 33824
SuperWord::first_node: 33802 is the first iteration node for 33707 (_clone_map.idx(nnn->_idx) = 815)
SuperWord::hoist_loads_in_graph replacing MemNode::Memory(1) edge in 33707 with one from 33824
SuperWord::first_node: 33802 is the first iteration node for 33700 (_clone_map.idx(nnn->_idx) = 815)
SuperWord::hoist_loads_in_graph replacing MemNode::Memory(1) edge in 33700 with one from 33824
SuperWord::first_node: 33802 is the first iteration node for 33634 (_clone_map.idx(nnn->_idx) = 815)
SuperWord::hoist_loads_in_graph replacing MemNode::Memory(1) edge in 33634 with one from 33824
SuperWord::first_node: 33802 is the first iteration node for 815 (_clone_map.idx(nnn->_idx) = 815)
SuperWord::hoist_loads_in_graph replacing MemNode::Memory(1) edge in 815 with one from 33824
SuperWord::construct_bb: List of generations:   0:15  1:12  2:11  3:8  4:7  5:4  6:3  7:0 
SWPointer::output: print loop before create_reserve_version_of_loop
    Loop: N33821/N2871  counted [int,43),+8 (2147483648 iters)  main has_sfpt strip_mined
    C ID:33170 33821	CountedLoop	===  33821  33170  2871  [[ 33785  33792  33799  33801  33820  33821  33699  33824  33706  38  33633  33166 ]]  {33171:15} inner stride: 8 main of N33821 strip mined !orig=[33716],[33641],[33171],[33161],[1840] !jvms: Test::main @ bci:2349
Segmentation fault (core dumped)

Comments
URL: https://hg.openjdk.java.net/jdk/jdk/rev/fe10ad38509f User: chagedorn Date: 2020-07-22 10:06:27 +0000
22-07-2020

http://cr.openjdk.java.net/~chagedorn/8247743/webrev.00/ The testcase creates a deep graph with a lot of nodes on a chain. When running with the specified test flags, it recursively calls Node::find_recur() for each node discovered which eventually results in a segmentation fault due to a stack overflow (around 10000 calls due to such a long chain of nodes). The fix just converts the recursive algorithm into an iterative one to avoid a segmentation fault. This is similar to JDK-8246203 [1]. I additionally removed Node::find_ctrl() and its special handling in the algorithm since it is not used. There is actually another problem with the recursive version. When running the testcase without -XX:CompileOnly=compiler/c2/TestFindNode, it will spin forever inside [2] because there is a debug_orig node cycle and the loop does not break based on the debug_orig nodes being visited. This is also fixed in the patch. [1] https://bugs.openjdk.java.net/browse/JDK-8246203 [2] http://hg.openjdk.java.net/jdk/jdk/file/e2622818f0bd/src/hotspot/share/opto/node.cpp#l1589
02-07-2020

Much faster command line flags which also triggers the problem with the same testcase: -XX:CompileCommand=option,*::*,bool,Vectorize,true -XX:+PrintOpto -XX:+TraceLoopOpts.
01-07-2020

ILW = Stack overflow in C2 verification/debug code (does not affect product), with CompileCommand VectorizeDebug, no workaround but disable compile command = MLM = P4
18-06-2020