diff --git a/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java b/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java index 3ea862c53013..048cf0ab00c9 100644 --- a/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java +++ b/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java @@ -18,6 +18,7 @@ package org.apache.lucene.util.graph; import static org.apache.lucene.util.automaton.Operations.DEFAULT_DETERMINIZE_WORK_LIMIT; +import static org.apache.lucene.util.automaton.Operations.MAX_RECURSION_LEVEL; import java.io.IOException; import java.util.ArrayList; @@ -46,7 +47,6 @@ */ public final class GraphTokenStreamFiniteStrings { - private static final int MAX_RECURSION_DEPTH = 1024; private AttributeSource[] tokens = new AttributeSource[4]; private final Automaton det; private final Transition transition = new Transition(); @@ -270,9 +270,13 @@ private static void articulationPointsRecurse( int numT = a.initTransition(state, t); for (int i = 0; i < numT; i++) { a.getNextTransition(t); - if (visited.get(t.dest) == false && d < MAX_RECURSION_DEPTH) { + if (visited.get(t.dest) == false) { parent[t.dest] = state; - articulationPointsRecurse(a, t.dest, d + 1, depth, low, parent, visited, points); + if (d < MAX_RECURSION_LEVEL) { + articulationPointsRecurse(a, t.dest, d + 1, depth, low, parent, visited, points); + } else { + continue; + } childCount++; if (low[t.dest] >= depth[state]) { isArticulation = true; diff --git a/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java b/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java index 88a14696cac8..56fadc901445 100644 --- a/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java +++ b/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java @@ -16,6 +16,8 @@ */ package org.apache.lucene.util.graph; +import static org.apache.lucene.util.automaton.Operations.MAX_RECURSION_LEVEL; + import java.util.ArrayList; import java.util.Iterator; import org.apache.lucene.analysis.TokenStream; @@ -663,12 +665,11 @@ public void testMultipleSidePathsWithGaps() throws Exception { } public void testLongTokenStreamStackOverflowError() throws Exception { + ArrayList tokens = new ArrayList() { { - add(token("turbo", 1, 1)); - add(token("fast", 0, 2)); - add(token("charged", 1, 1)); + add(token("fast", 1, 1)); add(token("wi", 1, 1)); add(token("wifi", 0, 2)); add(token("fi", 1, 1)); @@ -682,6 +683,33 @@ public void testLongTokenStreamStackOverflowError() throws Exception { TokenStream ts = new CannedTokenStream(tokens.toArray(new Token[0])); GraphTokenStreamFiniteStrings graph = new GraphTokenStreamFiniteStrings(ts); - graph.articulationPoints(); // This will cause a java.lang.StackOverflowError + + Iterator it = graph.getFiniteStrings(); + assertTrue(it.hasNext()); + it.next(); + assertTrue(it.hasNext()); + it.next(); + assertFalse(it.hasNext()); + + int[] points = graph.articulationPoints(); // This will cause a java.lang.StackOverflowError + assertEquals(points[0], 1); + assertEquals(points[1], 3); + assertEquals(points.length, MAX_RECURSION_LEVEL - 2); + + assertFalse(graph.hasSidePath(0)); + it = graph.getFiniteStrings(0, 1); + assertTrue(it.hasNext()); + assertTokenStream(it.next(), new String[] {"fast"}, new int[] {1}); + assertFalse(it.hasNext()); + Term[] terms = graph.getTerms("field", 0); + assertArrayEquals(terms, new Term[] {new Term("field", "fast")}); + + assertTrue(graph.hasSidePath(1)); + it = graph.getFiniteStrings(1, 3); + assertTrue(it.hasNext()); + assertTokenStream(it.next(), new String[] {"wi", "fi"}, new int[] {1, 1}); + assertTrue(it.hasNext()); + assertTokenStream(it.next(), new String[] {"wifi"}, new int[] {1}); + assertFalse(it.hasNext()); } }