Skip to content

Commit 5fffb18

Browse files
committed
Rewrite recursion into iteration for rule liveness analysis.
This fixes bug #219. Tested as follows (all tests passed): bash -c "ulimit -s 256; time ./run_tests.py" Original test that revealed the problematic recursive functions: bash -c "ulimit -s 256; echo run | gdb --args ./re2c overflow-1.re"
1 parent 02e5d79 commit 5fffb18

File tree

1 file changed

+48
-26
lines changed

1 file changed

+48
-26
lines changed

src/dfa/dead_rules.cc

+48-26
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
#include "src/util/check.h"
1414
#include "src/util/forbid_copy.h"
1515

16-
namespace re2c {
17-
18-
struct tcmd_t;
19-
2016
// note [unreachable rules]
2117
//
2218
// TDFA may contain useless final states. Such states may appear as a result of:
@@ -52,6 +48,11 @@ struct tcmd_t;
5248
// fallback states are not affected by these transformations, so we can calculate them here and save
5349
// for future use.
5450

51+
namespace re2c {
52+
namespace {
53+
54+
struct tcmd_t;
55+
5556
// reversed DFA
5657
struct RevDfa {
5758
struct arc_t {
@@ -108,30 +109,49 @@ struct RevDfa {
108109
FORBID_COPY(RevDfa);
109110
};
110111

111-
static void backprop(const RevDfa& rdfa, bool* live, size_t rule, size_t state) {
112-
// "none-rule" is unreachable from final states: be careful to mask it before propagating
113-
const RevDfa::state_t& s = rdfa.states[state];
114-
if (rule == rdfa.nrules) {
115-
rule = s.rule;
116-
}
117-
118-
// If the rule has already been set, than either it's a loop, or another branch of backward
119-
// propagation has already been here, in both cases we should stop: there's nothing new to
120-
// propagate.
121-
bool& l = live[rule * rdfa.nstates + state];
122-
if (l) return;
123-
l = true;
124-
125-
for (const RevDfa::arc_t* a = s.arcs; a; a = a->next) {
126-
backprop(rdfa, live, rule, a->dest);
127-
}
128-
}
112+
struct DfsBackprop {
113+
size_t state;
114+
size_t rule;
115+
const RevDfa::arc_t* arc;
116+
};
129117

130-
static void liveness_analyses(const RevDfa& rdfa, bool* live) {
118+
static void liveness_analysis(const RevDfa& rdfa, bool* live) {
119+
std::vector<DfsBackprop> stack;
131120
for (size_t i = 0; i < rdfa.nstates; ++i) {
132121
const RevDfa::state_t& s = rdfa.states[i];
133-
if (s.fallthru) {
134-
backprop(rdfa, live, s.rule, i);
122+
if (!s.fallthru) continue;
123+
124+
// Backward-propagate liveness from fallthrough state, following reversed DFA arcs.
125+
stack.push_back({i, s.rule, nullptr});
126+
while (!stack.empty()) {
127+
// Ensure that the reference to stack top won't be accidentally invalidated on push.
128+
if (stack.size() == stack.capacity()) stack.reserve(stack.size() * 2);
129+
DfsBackprop& x = stack.back();
130+
131+
const RevDfa::state_t& t = rdfa.states[x.state];
132+
133+
if (x.arc == nullptr) {
134+
// "none-rule" is unreachable from final states: mask it before propagating.
135+
if (x.rule == rdfa.nrules) {
136+
x.rule = t.rule;
137+
}
138+
// If the rule has already been set, than either it's a loop, or another branch of
139+
// backward propagation has already been here, in both cases we should stop: there's
140+
// nothing new to propagate.
141+
bool& l = live[x.rule * rdfa.nstates + x.state];
142+
if (!l) {
143+
l = true;
144+
x.arc = t.arcs;
145+
}
146+
} else {
147+
x.arc = x.arc->next;
148+
}
149+
150+
if (x.arc == nullptr) {
151+
stack.pop_back(); // all arcs followed, this state is finished
152+
} else {
153+
stack.push_back({x.arc->dest, x.rule, nullptr}); // follow next arc
154+
}
135155
}
136156
}
137157
}
@@ -282,6 +302,8 @@ static void remove_dead_final_states_with_eof_rule(Tdfa& dfa) {
282302
}
283303
}
284304

305+
} // anonymous namespace
306+
285307
void cutoff_dead_rules(Tdfa& dfa, const opt_t* opts, const std::string& cond, Msg& msg) {
286308
if (opts->eof != NOEOF) {
287309
// See note [end-of-input rule].
@@ -295,7 +317,7 @@ void cutoff_dead_rules(Tdfa& dfa, const opt_t* opts, const std::string& cond, Ms
295317
bool* fallthru = live + nl - ns;
296318
memset(live, 0, nl * sizeof(bool));
297319

298-
liveness_analyses(rdfa, live);
320+
liveness_analysis(rdfa, live);
299321

300322
warn_dead_rules(dfa, cond, live, msg);
301323
remove_dead_final_states(dfa, fallthru);

0 commit comments

Comments
 (0)