help-bison
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]