8247743: Segmentation fault in debug builds due to stack overflow in find_recur with deep graphs

Replace the recursive algorithm of Node::find() by an iterative one to avoid a stack overflow crash with deep graphs.

Reviewed-by: kvn, thartmann
This commit is contained in:
Christian Hagedorn 2020-07-22 10:31:37 +02:00
parent 4f99e1fb11
commit 18cf3d8080
3 changed files with 169 additions and 61 deletions

View File

@ -1554,78 +1554,95 @@ jfloat Node::getf() const {
#ifndef PRODUCT
//------------------------------find------------------------------------------
// Find a neighbor of this Node with the given _idx
// If idx is negative, find its absolute value, following both _in and _out.
static void find_recur(Compile* C, Node* &result, Node *n, int idx, bool only_ctrl,
VectorSet* old_space, VectorSet* new_space ) {
int node_idx = (idx >= 0) ? idx : -idx;
if (NotANode(n)) return; // Gracefully handle NULL, -1, 0xabababab, etc.
// Contained in new_space or old_space? Check old_arena first since it's mostly empty.
VectorSet *v = C->old_arena()->contains(n) ? old_space : new_space;
if( v->test(n->_idx) ) return;
if( (int)n->_idx == node_idx
debug_only(|| n->debug_idx() == node_idx) ) {
if (result != NULL)
tty->print("find: " INTPTR_FORMAT " and " INTPTR_FORMAT " both have idx==%d\n",
(uintptr_t)result, (uintptr_t)n, node_idx);
result = n;
}
v->set(n->_idx);
for( uint i=0; i<n->len(); i++ ) {
if( only_ctrl && !(n->is_Region()) && (n->Opcode() != Op_Root) && (i != TypeFunc::Control) ) continue;
find_recur(C, result, n->in(i), idx, only_ctrl, old_space, new_space );
}
// Search along forward edges also:
if (idx < 0 && !only_ctrl) {
for( uint j=0; j<n->outcnt(); j++ ) {
find_recur(C, result, n->raw_out(j), idx, only_ctrl, old_space, new_space );
}
}
#ifdef ASSERT
// Search along debug_orig edges last, checking for cycles
Node* orig = n->debug_orig();
if (orig != NULL) {
do {
if (NotANode(orig)) break;
find_recur(C, result, orig, idx, only_ctrl, old_space, new_space );
orig = orig->debug_orig();
} while (orig != NULL && orig != n->debug_orig());
}
#endif //ASSERT
}
// call this from debugger:
Node* find_node(Node* n, int idx) {
// Call this from debugger:
Node* find_node(Node* n, const int idx) {
return n->find(idx);
}
// call this from debugger with root node as default:
Node* find_node(int idx) {
// Call this from debugger with root node as default:
Node* find_node(const int idx) {
return Compile::current()->root()->find(idx);
}
//------------------------------find-------------------------------------------
Node* Node::find(int idx) const {
VectorSet old_space, new_space;
Node* result = NULL;
find_recur(Compile::current(), result, (Node*) this, idx, false, &old_space, &new_space);
return result;
// Call this from debugger:
Node* find_ctrl(Node* n, const int idx) {
return n->find_ctrl(idx);
}
// Call this from debugger with root node as default:
Node* find_ctrl(const int idx) {
return Compile::current()->root()->find_ctrl(idx);
}
//------------------------------find_ctrl--------------------------------------
// Find an ancestor to this node in the control history with given _idx
Node* Node::find_ctrl(int idx) const {
VectorSet old_space, new_space;
Node* Node::find_ctrl(int idx) {
return find(idx, true);
}
//------------------------------find-------------------------------------------
// Tries to find the node with the index |idx| starting from this node. If idx is negative,
// the search also includes forward (out) edges. Returns NULL if not found.
// If only_ctrl is set, the search will only be done on control nodes. Returns NULL if
// not found or if the node to be found is not a control node (search will not find it).
Node* Node::find(const int idx, bool only_ctrl) {
ResourceMark rm;
VectorSet old_space;
VectorSet new_space;
Node_List worklist;
Arena* old_arena = Compile::current()->old_arena();
add_to_worklist(this, &worklist, old_arena, &old_space, &new_space);
Node* result = NULL;
find_recur(Compile::current(), result, (Node*)this, idx, true, &old_space, &new_space);
int node_idx = (idx >= 0) ? idx : -idx;
for (uint list_index = 0; list_index < worklist.size(); list_index++) {
Node* n = worklist[list_index];
if ((int)n->_idx == node_idx debug_only(|| n->debug_idx() == node_idx)) {
if (result != NULL) {
tty->print("find: " INTPTR_FORMAT " and " INTPTR_FORMAT " both have idx==%d\n",
(uintptr_t)result, (uintptr_t)n, node_idx);
}
result = n;
}
for (uint i = 0; i < n->len(); i++) {
if (!only_ctrl || n->is_Region() || (n->Opcode() == Op_Root) || (i == TypeFunc::Control)) {
// If only_ctrl is set: Add regions, the root node, or control inputs only
add_to_worklist(n->in(i), &worklist, old_arena, &old_space, &new_space);
}
}
// Also search along forward edges if idx is negative and the search is not done on control nodes only
if (idx < 0 && !only_ctrl) {
for (uint i = 0; i < n->outcnt(); i++) {
add_to_worklist(n->raw_out(i), &worklist, old_arena, &old_space, &new_space);
}
}
#ifdef ASSERT
// Search along debug_orig edges last
Node* orig = n->debug_orig();
while (orig != NULL && add_to_worklist(orig, &worklist, old_arena, &old_space, &new_space)) {
orig = orig->debug_orig();
}
#endif // ASSERT
}
return result;
}
#endif
bool Node::add_to_worklist(Node* n, Node_List* worklist, Arena* old_arena, VectorSet* old_space, VectorSet* new_space) {
if (NotANode(n)) {
return false; // Gracefully handle NULL, -1, 0xabababab, etc.
}
#ifndef PRODUCT
// Contained in new_space or old_space? Check old_arena first since it's mostly empty.
VectorSet* v = old_arena->contains(n) ? old_space : new_space;
if (!v->test_set(n->_idx)) {
worklist->push(n);
return true;
}
return false;
}
// -----------------------------Name-------------------------------------------
extern const char *NodeClassNames[];
@ -2227,7 +2244,7 @@ void Node::verify(Node* n, int verify_depth) {
}
}
}
#endif
#endif // not PRODUCT
//------------------------------walk-------------------------------------------
// Graph walk, with both pre-order and post-order functions

View File

@ -1118,10 +1118,11 @@ private:
void walk_(NFunc pre, NFunc post, void *env, VectorSet &visited);
//----------------- Printing, etc
public:
#ifndef PRODUCT
Node* find(int idx) const; // Search the graph for the given idx.
Node* find_ctrl(int idx) const; // Search control ancestors for the given idx.
static bool add_to_worklist(Node* n, Node_List* worklist, Arena* old_arena, VectorSet* old_space, VectorSet* new_space);
public:
Node* find(int idx, bool only_ctrl = false); // Search the graph for the given idx.
Node* find_ctrl(int idx); // Search control ancestors for the given idx.
void dump() const { dump("\n"); } // Print this node.
void dump(const char* suffix, bool mark = false, outputStream *st = tty) const; // Print this node.
void dump(int depth) const; // Print this node, recursively to depth d

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8247743
* @requires vm.debug == true & vm.flavor == "server"
* @summary Test which uses some special flags in order to test Node::find() in debug builds which could result in an endless loop or a stack overflow crash.
*
* @run main/othervm -Xbatch -XX:CompileCommand=option,*::*,bool,Vectorize,true -XX:+PrintOpto -XX:+TraceLoopOpts compiler.c2.TestFindNode
*/
package compiler.c2;
public class TestFindNode {
static volatile int[] iArr;
static volatile int x;
static int[] iArr2 = new int[100];
static int[] iArr3 = new int[100];
public static void main(String[] arr) {
for (int i = 0; i < 2000; i++) {
test();
}
}
public static void test() {
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
for (int i = 0; i < 50; i++) {
iArr2[i] = iArr3[i];
}
}
}