summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAkim Demaille <demaille@gostai.com>2011-03-09 21:10:35 +0100
committerAkim Demaille <demaille@gostai.com>2011-03-09 21:10:35 +0100
commita4d1bf6a9cdd337fc113c5a3fc7424e7491d6ea5 (patch)
tree0dda502bac89f9cbff055073d1bd2df99be6479d /src
parent17d7bf83d02e2272c54d3486075091156d5d649f (diff)
downloadbison-a4d1bf6a9cdd337fc113c5a3fc7424e7491d6ea5.tar.gz
named references: fix double free.candidates/named-ref-free
In `rhs[name]: "a" | "b"', do not free "name" twice. Reported by Tys Lefering. <http://lists.gnu.org/archive/html/bug-bison/2010-06/msg00002.html> * src/named-ref.h, src/named-ref.c (named_ref_copy): New. * src/parse-gram.y (current_lhs): Rename as... (current_lhs_symbol): this. (current_lhs): New function. Use it to free the current lhs named reference. * src/reader.c: Bind lhs to a copy of the current named reference. * src/symlist.c: Rely on free (0) being valid. * tests/named-refs.at: Test this. (cherry picked from commit 8f462efe923947cc4e72deea5b0fa93a5f88000d) Conflicts: src/parse-gram.y
Diffstat (limited to 'src')
-rw-r--r--src/named-ref.c6
-rw-r--r--src/named-ref.h3
-rw-r--r--src/parse-gram.y29
-rw-r--r--src/reader.c2
-rw-r--r--src/symlist.c3
5 files changed, 36 insertions, 7 deletions
diff --git a/src/named-ref.c b/src/named-ref.c
index 4bf3da12..132c7414 100644
--- a/src/named-ref.c
+++ b/src/named-ref.c
@@ -33,6 +33,12 @@ named_ref_new (uniqstr id, location loc)
return res;
}
+named_ref *
+named_ref_copy (const named_ref *r)
+{
+ return named_ref_new (r->id, r->loc);
+}
+
void
named_ref_free (named_ref *r)
{
diff --git a/src/named-ref.h b/src/named-ref.h
index 0f96e463..46d9d8d4 100644
--- a/src/named-ref.h
+++ b/src/named-ref.h
@@ -37,6 +37,9 @@ typedef struct named_ref
/* Allocate a named reference object. */
named_ref *named_ref_new (uniqstr id, location loc);
+/* Allocate and return a copy. */
+named_ref *named_ref_copy (const named_ref *r);
+
/* Free a named reference object. */
void named_ref_free (named_ref *r);
diff --git a/src/parse-gram.y b/src/parse-gram.y
index f79b0e92..514b5d79 100644
--- a/src/parse-gram.y
+++ b/src/parse-gram.y
@@ -56,10 +56,28 @@ static char const *char_name (char);
static int current_prec = 0;
static location current_lhs_location;
static named_ref *current_lhs_named_ref;
- static symbol *current_lhs;
+ static symbol *current_lhs_symbol;
static symbol_class current_class = unknown_sym;
static uniqstr current_type = NULL;
+ /** Set the new current left-hand side symbol, possibly common
+ * to several right-hand side parts of rule.
+ */
+ static
+ void
+ current_lhs(symbol *sym, location loc, named_ref *ref)
+ {
+ current_lhs_symbol = sym;
+ current_lhs_location = loc;
+ /* In order to simplify memory management, named references for lhs
+ are always assigned by deep copy into the current symbol_list
+ node. This is because a single named-ref in the grammar may
+ result in several uses when the user factors lhs between several
+ rules using "|". Therefore free the parser's original copy. */
+ free (current_lhs_named_ref);
+ current_lhs_named_ref = ref;
+ }
+
#define YYTYPE_INT16 int_fast16_t
#define YYTYPE_INT8 int_fast8_t
#define YYTYPE_UINT16 uint_fast16_t
@@ -569,8 +587,11 @@ rules_or_grammar_declaration:
;
rules:
- id_colon named_ref.opt { current_lhs = $1; current_lhs_location = @1;
- current_lhs_named_ref = $2; } rhses.1
+ id_colon named_ref.opt { current_lhs ($1, @1, $2); } rhses.1
+ {
+ /* Free the current lhs. */
+ current_lhs (0, @1, 0);
+ }
;
rhses.1:
@@ -581,7 +602,7 @@ rhses.1:
rhs:
/* Nothing. */
- { grammar_current_rule_begin (current_lhs, current_lhs_location,
+ { grammar_current_rule_begin (current_lhs_symbol, current_lhs_location,
current_lhs_named_ref); }
| rhs symbol named_ref.opt
{ grammar_current_rule_symbol_append ($2, @2, $3); }
diff --git a/src/reader.c b/src/reader.c
index 6fc14a3e..2289d26e 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -231,7 +231,7 @@ grammar_current_rule_begin (symbol *lhs, location loc,
p = grammar_symbol_append (lhs, loc);
if (lhs_name)
- assign_named_ref(p, lhs_name);
+ assign_named_ref (p, named_ref_copy (lhs_name));
current_rule = grammar_end;
diff --git a/src/symlist.c b/src/symlist.c
index e717c3e1..190d0073 100644
--- a/src/symlist.c
+++ b/src/symlist.c
@@ -151,8 +151,7 @@ symbol_list_free (symbol_list *list)
for (node = list; node; node = next)
{
next = node->next;
- if (node->named_ref)
- named_ref_free (node->named_ref);
+ named_ref_free (node->named_ref);
free (node);
}
}