cex: fix parse state leaks

* src/parse_simulation.c: Fix bug in parse_state_free.
Free new_root when simulate_reduction generates zero states.

* src/parse-simulation.c, src/parse-simulation.h
(parse_state_list, parse_state_list_append): New.
* src/parse-simulation.c, src/parse-simulation.h,
* src/counterexample.c: Replace all uses of lists of parse states and
appends to parse_state_lists with the new API.
This commit is contained in:
Vincent Imbimbo
2020-05-21 22:13:12 -04:00
committed by Akim Demaille
parent 35c4a8e65e
commit 150b2318ed
3 changed files with 53 additions and 39 deletions

View File

@@ -701,7 +701,8 @@ production_step (search_state *ss, int parser_state)
{ {
const state_item *other_si = parse_state_tail (ss->states[1 - parser_state]); const state_item *other_si = parse_state_tail (ss->states[1 - parser_state]);
symbol_number other_sym = item_number_as_symbol_number (*other_si->item); symbol_number other_sym = item_number_as_symbol_number (*other_si->item);
gl_list_t prods = simulate_production (ss->states[parser_state], other_sym); parse_state_list prods =
simulate_production (ss->states[parser_state], other_sym);
int complexity = ss->complexity + PRODUCTION_COST; int complexity = ss->complexity + PRODUCTION_COST;
gl_list_iterator_t it = gl_list_iterator (prods); gl_list_iterator_t it = gl_list_iterator (prods);
@@ -751,7 +752,8 @@ reduction_step (search_state *ss, const item_number *conflict_item,
} }
// FIXME: search_state *new_root = copy_search_state (ss); // FIXME: search_state *new_root = copy_search_state (ss);
gl_list_t reduced = simulate_reduction (ps, rule_len, symbol_set); parse_state_list reduced =
simulate_reduction (ps, rule_len, symbol_set);
gl_list_iterator_t it = gl_list_iterator (reduced); gl_list_iterator_t it = gl_list_iterator (reduced);
parse_state *reduced_ps; parse_state *reduced_ps;
while (gl_list_iterator_next (&it, (const void **) &reduced_ps, NULL)) while (gl_list_iterator_next (&it, (const void **) &reduced_ps, NULL))
@@ -787,7 +789,7 @@ search_state_prepend (search_state *ss, symbol_number sym, bitset guide)
if (prod1 != SI_PRODUCTION (si2src)) if (prod1 != SI_PRODUCTION (si2src))
{ {
int prod_state = prod1 ? 0 : 1; int prod_state = prod1 ? 0 : 1;
gl_list_t prev = parser_prepend (ss->states[prod_state]); parse_state_list prev = parser_prepend (ss->states[prod_state]);
gl_list_iterator_t iter = gl_list_iterator (prev); gl_list_iterator_t iter = gl_list_iterator (prev);
parse_state *ps = NULL; parse_state *ps = NULL;
while (gl_list_iterator_next (&iter, (const void **)&ps, NULL)) while (gl_list_iterator_next (&iter, (const void **)&ps, NULL))
@@ -813,8 +815,8 @@ search_state_prepend (search_state *ss, symbol_number sym, bitset guide)
int complexity_cost = prod1 ? PRODUCTION_COST : UNSHIFT_COST; int complexity_cost = prod1 ? PRODUCTION_COST : UNSHIFT_COST;
complexity_cost *= 2; complexity_cost *= 2;
gl_list_t prev1 = parser_prepend (ss->states[0]); parse_state_list prev1 = parser_prepend (ss->states[0]);
gl_list_t prev2 = parser_prepend (ss->states[1]); parse_state_list prev2 = parser_prepend (ss->states[1]);
// loop through each pair of possible prepend states and append search // loop through each pair of possible prepend states and append search
// states for each pair where the parser states correspond to the same // states for each pair where the parser states correspond to the same
@@ -915,8 +917,8 @@ generate_next_states (search_state *ss, state_item *conflict1,
if (*si1->item == *si2->item) if (*si1->item == *si2->item)
{ {
int complexity = ss->complexity + 2 * SHIFT_COST; int complexity = ss->complexity + 2 * SHIFT_COST;
gl_list_t trans1 = simulate_transition (ps1); parse_state_list trans1 = simulate_transition (ps1);
gl_list_t trans2 = simulate_transition (ps2); parse_state_list trans2 = simulate_transition (ps2);
gl_list_iterator_t it1 = gl_list_iterator (trans1); gl_list_iterator_t it1 = gl_list_iterator (trans1);
parse_state *tps1; parse_state *tps1;
while (gl_list_iterator_next (&it1, (const void **) &tps1, NULL)) while (gl_list_iterator_next (&it1, (const void **) &tps1, NULL))

View File

@@ -199,7 +199,8 @@ void
free_parse_state (parse_state *original_ps) free_parse_state (parse_state *original_ps)
{ {
bool free_contents = true; bool free_contents = true;
for (parse_state *ps = original_ps; ps && free_contents; ps = ps->parent) parse_state *parent_ps = NULL;
for (parse_state *ps = original_ps; ps && free_contents; ps = parent_ps)
{ {
--ps->reference_count; --ps->reference_count;
free_contents = (ps->reference_count == 1 && ps->free_contents_early) free_contents = (ps->reference_count == 1 && ps->free_contents_early)
@@ -213,11 +214,11 @@ free_parse_state (parse_state *original_ps)
if (ps->derivs.contents) if (ps->derivs.contents)
derivation_list_free (ps->derivs.contents); derivation_list_free (ps->derivs.contents);
} }
parent_ps = ps->parent;
if (ps->reference_count <= 0) if (ps->reference_count <= 0)
{ {
free (ps); free (ps);
++frees; ++frees;
break;
} }
} }
} }
@@ -303,7 +304,7 @@ list_flatten_and_split (gl_list_t *list, gl_list_t *rets, int split, int n,
} }
} }
static gl_list_t static parse_state_list
parse_state_list_new (void) parse_state_list_new (void)
{ {
return gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, return gl_list_create_empty (GL_LINKED_LIST, NULL, NULL,
@@ -311,6 +312,12 @@ parse_state_list_new (void)
true); true);
} }
void parse_state_list_append (parse_state_list pl, parse_state *ps)
{
parse_state_retain (ps);
gl_list_add_last (pl, ps);
}
// Emulates a reduction on a parse state by popping some amount of // Emulates a reduction on a parse state by popping some amount of
// derivations and state_items off of the parse_state and returning // derivations and state_items off of the parse_state and returning
// the result in ret. Returns the derivation of what's popped. // the result in ret. Returns the derivation of what's popped.
@@ -397,7 +404,7 @@ parse_state_lists (parse_state *ps, gl_list_t *sitems,
* nullable symbols whenever possible from the given state_item. * nullable symbols whenever possible from the given state_item.
*/ */
void void
nullable_closure (parse_state *ps, state_item *si, gl_list_t state_list) nullable_closure (parse_state *ps, state_item *si, parse_state_list state_list)
{ {
parse_state *current_ps = ps; parse_state *current_ps = ps;
state_item_number prev_sin = si - state_items; state_item_number prev_sin = si - state_items;
@@ -413,8 +420,7 @@ nullable_closure (parse_state *ps, state_item *si, gl_list_t state_list)
current_ps = copy_parse_state (false, current_ps); current_ps = copy_parse_state (false, current_ps);
ps_si_append (current_ps, nsi); ps_si_append (current_ps, nsi);
ps_derivs_append (current_ps, derivation_new_leaf (sp)); ps_derivs_append (current_ps, derivation_new_leaf (sp));
parse_state_retain (current_ps); parse_state_list_append (state_list, current_ps);
gl_list_add_last (state_list, current_ps);
} }
} }
@@ -435,8 +441,7 @@ simulate_transition (parse_state *ps)
parse_state *next_ps = copy_parse_state (false, ps); parse_state *next_ps = copy_parse_state (false, ps);
ps_si_append (next_ps, state_items + si_next); ps_si_append (next_ps, state_items + si_next);
ps_derivs_append (next_ps, derivation_new_leaf (sym)); ps_derivs_append (next_ps, derivation_new_leaf (sym));
parse_state_retain (next_ps); parse_state_list_append (result, next_ps);
gl_list_add_last (result, next_ps);
nullable_closure (next_ps, state_items + si_next, result); nullable_closure (next_ps, state_items + si_next, result);
return result; return result;
@@ -481,8 +486,7 @@ simulate_production (parse_state *ps, symbol_number compat_sym)
continue; continue;
parse_state *next_ps = copy_parse_state (false, ps); parse_state *next_ps = copy_parse_state (false, ps);
ps_si_append (next_ps, next); ps_si_append (next_ps, next);
parse_state_retain (next_ps); parse_state_list_append (result, next_ps);
gl_list_add_last (result, next_ps);
if (next_ps->depth >= 0) if (next_ps->depth >= 0)
++next_ps->depth; ++next_ps->depth;
nullable_closure (next_ps, next, result); nullable_closure (next_ps, next, result);
@@ -520,8 +524,7 @@ simulate_reduction (parse_state *ps, int rule_len, bitset symbol_set)
{ {
state_item *tail = (state_item *) new_root->state_items.tail_elt; state_item *tail = (state_item *) new_root->state_items.tail_elt;
ps_si_append (new_root, state_items + si_trans[tail - state_items]); ps_si_append (new_root, state_items + si_trans[tail - state_items]);
parse_state_retain (new_root); parse_state_list_append (result, new_root);
gl_list_add_last (result, new_root);
} }
else else
{ {
@@ -529,22 +532,31 @@ simulate_reduction (parse_state *ps, int rule_len, bitset symbol_set)
// with possible source state-items. // with possible source state-items.
const state_item *head = ps->state_items.head_elt; const state_item *head = ps->state_items.head_elt;
gl_list_t prev = lssi_reverse_production (head, symbol_set); gl_list_t prev = lssi_reverse_production (head, symbol_set);
gl_list_iterator_t it = gl_list_iterator (prev); // TODO: better understand what causes this case.
state_item *psis; if (gl_list_size (prev) == 0)
while (gl_list_iterator_next (&it, (const void **) &psis, NULL))
{ {
//Prepend the result from the reverse production // new_root needs to have an RC of 1 to be freed correctly here.
parse_state *copy = copy_parse_state (true, new_root); parse_state_retain (new_root);
ps_si_prepend (copy, psis); free_parse_state (new_root);
}
else
{
gl_list_iterator_t it = gl_list_iterator (prev);
state_item *psis;
while (gl_list_iterator_next (&it, (const void **) &psis, NULL))
{
//Prepend the result from the reverse production
parse_state *copy = copy_parse_state (true, new_root);
ps_si_prepend (copy, psis);
// Append the left hand side to the end of the parser state // Append the left hand side to the end of the parser state
copy = copy_parse_state (false, copy); copy = copy_parse_state (false, copy);
struct si_chunk *sis = &copy->state_items; struct si_chunk *sis = &copy->state_items;
const state_item *tail = sis->tail_elt; const state_item *tail = sis->tail_elt;
ps_si_append (copy, state_items + si_trans[tail - state_items]); ps_si_append (copy, state_items + si_trans[tail - state_items]);
parse_state_retain (copy); parse_state_list_append (result, copy);
gl_list_add_last (result, copy); nullable_closure (copy, (state_item *) sis->tail_elt, result);
nullable_closure (copy, (state_item *) sis->tail_elt, result); }
} }
gl_list_free (prev); gl_list_free (prev);
} }
@@ -564,11 +576,10 @@ parser_prepend (parse_state *ps)
BITSET_FOR_EACH (biter, prev, sin, 0) BITSET_FOR_EACH (biter, prev, sin, 0)
{ {
parse_state *copy = copy_parse_state (true, ps); parse_state *copy = copy_parse_state (true, ps);
parse_state_retain (copy);
ps_si_prepend (copy, state_items + sin); ps_si_prepend (copy, state_items + sin);
if (SI_TRANSITION (head)) if (SI_TRANSITION (head))
ps_derivs_prepend (copy, derivation_new_leaf (prepend_sym)); ps_derivs_prepend (copy, derivation_new_leaf (prepend_sym));
gl_list_add_last (result, copy); parse_state_list_append (result, copy);
} }
return result; return result;
} }

View File

@@ -72,6 +72,7 @@
*/ */
typedef struct parse_state parse_state; typedef struct parse_state parse_state;
typedef gl_list_t parse_state_list;
parse_state *new_parse_state (const state_item *conflict); parse_state *new_parse_state (const state_item *conflict);
@@ -110,22 +111,22 @@ void parse_state_lists (parse_state *ps, gl_list_t *state_items,
/* Look at the tail state-item of the parse state and transition on the symbol /* Look at the tail state-item of the parse state and transition on the symbol
* after its dot. The symbol gets added to derivs, and the resulting state-item * after its dot. The symbol gets added to derivs, and the resulting state-item
* is appended to state-items. */ * is appended to state-items. */
gl_list_t simulate_transition (parse_state *ps); parse_state_list simulate_transition (parse_state *ps);
/* Look at all of the productions for the non-terminal following the dot in the tail /* Look at all of the productions for the non-terminal following the dot in the tail
* state-item. Appends to state-items each production state-item which may start with * state-item. Appends to state-items each production state-item which may start with
* compat_sym. */ * compat_sym. */
gl_list_t simulate_production (parse_state *ps, symbol_number compat_sym); parse_state_list simulate_production (parse_state *ps, symbol_number compat_sym);
/* Removes the last rule_len state-items along with their derivations. A new state-item is /* Removes the last rule_len state-items along with their derivations. A new state-item is
* appended representing the goto after the reduction. A derivation for the non-terminal that * appended representing the goto after the reduction. A derivation for the non-terminal that
* was just reduced is appended which consists of the list of derivations that were just removed. */ * was just reduced is appended which consists of the list of derivations that were just removed. */
gl_list_t simulate_reduction (parse_state *ps, int rule_len, parse_state_list simulate_reduction (parse_state *ps, int rule_len,
bitset symbol_set); bitset symbol_set);
/* Generate states with a state-item prepended for each state-item that has a /* Generate states with a state-item prepended for each state-item that has a
* transition or production step to ps's head. */ * transition or production step to ps's head. */
gl_list_t parser_prepend (parse_state *ps); parse_state_list parser_prepend (parse_state *ps);
void print_parse_state (parse_state *ps); void print_parse_state (parse_state *ps);