[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: %destructor
From: |
Bob Rossi |
Subject: |
Re: %destructor |
Date: |
Fri, 26 Sep 2014 22:01:08 -0400 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
On Sat, Sep 27, 2014 at 12:23:37AM +0200, Hans Aberg wrote:
>
> > On 26 Sep 2014, at 21:58, Bob Rossi <address@hidden> wrote:
> >
> > On Fri, Sep 26, 2014 at 03:37:18PM +0200, Hans Aberg wrote:
>
> >>> The %destructor for result and result_list does not call free, but
> >>> instead calls gdbmi_result_free. gdbmi_result_free free's the result
> >>> (including the variable member of the result), and the result's next
> >>> pointer, and so on.
> >>>
> >>> Is it correct for me to call gdbmi_result_free($$) instead of free($$)?
> >>
> >> The %destructor is for making C style cleanup during an error recovery:
> >> the Bison generated parser will then skip forward, bypassing any normal
> >> deallocations in the actions. So first write the parser in normal C style,
> >> with deallocators in each instance matching the allocator used in the
> >> actions. Then add %destructor if needed for the error recovery.
> >
> > Unfortunately, this confused me more than clarified things.
> >
> > What are the 'normal deallocations in the actions?' I only ever put
> > allocations in the actions, never deallocations.
>
> Then it will leak for everything that you do no deallocate during normal,
> error-free parsing.
>
> > In the second sentence you mentioned I should write deallocators in each
> > instance matching the allocator used in the actions. THEN add
> > %destructor if needed for error recovery.
> >
> > Where do I put deallocators in the bison generator parser, besides
> > %destructor?
>
> I am normally using C++, which is doing the cleanup, but let’s try C
> (pseudocode):
>
> list:
> "[“ sequence[x] "]" { $$ = $x; }
> ;
>
> sequence:
> item[x] { $$ = make_list1($x); free($x); }
> | sequence[s] "," item[x] { $$ = make_list($s, $x); free($s); free($x); }
> ;
OK. Thanks for explaining. I took a different strategy here.
Maybe my strategy is wrong. You can see a slightly out of date version
of my grammar here,
https://github.com/brasko/gdbwire/blob/master/src/lib/gdbmi/gdbmi_grammar.y
Please consider the following type,
struct gdbmi_result {
enum gdbmi_result_kind kind;
char *variable;
union {
char *cstring;
struct gdbmi_result *result;
} variant;
struct gdbmi_result *next;
};
Please consider the following result_list rules,
result_list: {
$$ = NULL;
};
result_list: result_list COMMA result {
$$ = append_gdbmi_result ($1, $3);
};
result: opt_variable CSTRING {
$$ = gdbmi_result_alloc();
$$->variable = $1;
$$->kind = GDBMI_CSTRING;
$$->variant.cstring = strdup(gdbmi_text);
};
result: opt_variable tuple {
$$ = gdbmi_result_alloc();
$$->variable = $1;
$$->kind = GDBMI_TUPLE;
$$->variant.result = $2;
};
result: opt_variable list {
$$ = gdbmi_result_alloc();
$$->variable = $1;
$$->kind = GDBMI_LIST;
$$->variant.result = $2;
};
My approach is to build up $$. I never deallocate in the actions, and
valgrind claims I have no memory leaks in the unit tests. In the end, on
a successful parse, I end up with a 'struct gdbmi_result *' which has
the next pointer set, etc. Hopefully the above is an OK strategy.
The problem I'm facing is related to error handling for sure.
If I add this, (and I use malloc under the hood for all allocations)
%destructor { free($$); } result result_list;
I still have memory leaks (valgrind assures me). I'm not a bison expert,
and so it's not exactly obvious to me which items it chooses to call the
destructor on. If I change the free routine to
%destructor { gdbmi_result_free($$); } result result_list;
then the memory leaks go away (according to valgrind). gdbmi_result_free
free's each member in 'struct gdbmi_result' and also free's the next
field.
Since I don't understand what exactly Bison calls the destructor on, I'm
wondering,
1) If I free the entire struct gdbmi_result with gdbmi_result_free($$)
and I also have a destructor for $1 in the above examples,
%destructor { free($$); } variable
Is it possible I'll have a double free?
2) Because I'm using gdbmi_result_free($$) which also free's the next
pointer of a list, is it possible Bison will also call the destructor on
each member of the list item, causing a double free?
I know I'm not doing a great job here asking this question. Sorry.
If this is to unclear, I'll spend some time formulating a much more
precise question, which may perhaps help me answer my own question.
Thanks!
Bob Rossi
Re: %destructor, Bob Rossi, 2014/09/29