Avoid adding to closureBusy before all ATNConfig properties are set

Setting ATNConfig properties can change the hash code of the instance, leading
to cases where the closureBusy set places objects in the wrong buckets. While
this has not led to known cases of stack overflow, it has led to cases where
one or more buckets contains a large number of duplicate objects, and the set's
add operation goes from O(1) to O(n).
This commit is contained in:
Sam Harwell 2017-07-18 07:27:36 -05:00
parent c41426c87e
commit c8805ab584
1 changed files with 17 additions and 14 deletions

View File

@ -1541,11 +1541,6 @@ public class ParserATNSimulator extends ATNSimulator {
ATNConfig c = getEpsilonTarget(config, t, continueCollecting,
depth == 0, fullCtx, treatEofAsEpsilon);
if ( c!=null ) {
if (!t.isEpsilon() && !closureBusy.add(c)) {
// avoid infinite recursion for EOF* and EOF+
continue;
}
int newDepth = depth;
if ( config.state instanceof RuleStopState) {
assert !fullCtx;
@ -1555,11 +1550,6 @@ public class ParserATNSimulator extends ATNSimulator {
// come in handy and we avoid evaluating context dependent
// preds if this is > 0.
if (!closureBusy.add(c)) {
// avoid infinite recursion for right-recursive rules
continue;
}
if (_dfa != null && _dfa.isPrecedenceDfa()) {
int outermostPrecedenceReturn = ((EpsilonTransition)t).outermostPrecedenceReturn();
if (outermostPrecedenceReturn == _dfa.atnStartState.ruleIndex) {
@ -1568,17 +1558,30 @@ public class ParserATNSimulator extends ATNSimulator {
}
c.reachesIntoOuterContext++;
if (!closureBusy.add(c)) {
// avoid infinite recursion for right-recursive rules
continue;
}
configs.dipsIntoOuterContext = true; // TODO: can remove? only care when we add to set per middle of this method
assert newDepth > Integer.MIN_VALUE;
newDepth--;
if ( debug ) System.out.println("dips into outer ctx: "+c);
}
else if (t instanceof RuleTransition) {
else {
if (!t.isEpsilon() && !closureBusy.add(c)) {
// avoid infinite recursion for EOF* and EOF+
continue;
}
if (t instanceof RuleTransition) {
// latch when newDepth goes negative - once we step out of the entry context we can't return
if (newDepth >= 0) {
newDepth++;
}
}
}
closureCheckingStopState(c, configs, closureBusy, continueCollecting,
fullCtx, newDepth, treatEofAsEpsilon);