Re: yacc bug in reader.c:end_rule()

From: Giorgos Keramidas <keramida_at_ceid.upatras.gr>
Date: Mon, 24 Sep 2007 19:02:50 +0300
On 2007-09-24 18:50, Ruslan Ermilov <ru_at_freebsd.org> wrote:
> On Sun, Sep 23, 2007 at 04:13:15AM -0700, Darren Reed wrote:
> > Darren Reed wrote:
> >> There's a fairly obvious bug in yacc's reader.c but I'm not sure
> >> what the right fix is.
> >>
> >> Witness:
> >> end_rule()
> >> {
> >>    int i;
> >>
> >>    if (!last_was_action && plhs[nrules]->tag)
> >>    {
> >>       for (i = nitems - 1; pitem[i]; --i) continue;
> >>       if (pitem[i + 1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag)
> >> ...
> >> }
> >>
> >> ...clearly if pitem[nitems-1] == NULL (and nitems is the size of the
> >> array from [0,nitems-1]) then the if() will access beyond the bounds
> >> of the array.
> >>
> >> There's also the question of i being able to run below 0 too here.
>
> Not possible: first four pitem's are explicitly set to NULL in
> reader.c:initialize_grammar().
>
> >> I don't know if the bug is here or if the bug is elsewhere in yacc,
> >> but I doubt that the "fix" is s/i + 1/i/. *Maybe* "i = nitems - 2;"?
> >>
> >> The bug can be masked by using calloc instead of malloc and similar
> >> other tricks, but there is something more fundamentaly wrong here.
> >>
> >> Has anyone else run into this?
> >
> > The following sample grammar will exercise the bug:
> >
> > %{
> > %}
> >
> > %union {
> >        char            *ptr;
> > };
> >
> > %type   <ptr>   test
> > %%
> >
> > test:   | $$ = malloc(2);
>
> It crashes even when written "correctly" as:
>
> test:	| { $$ = malloc(2); }
>
> >        ;
> >
> > %%
> >
> > (The error here is that "test" has an undefined return.)
> >
> Try this patch.  It replaces a non-sense with a fix for the bug.
>
> %%%
> Index: reader.c
> ===================================================================
> RCS file: /home/ncvs/src/usr.bin/yacc/reader.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 reader.c
> --- reader.c	25 Aug 2002 13:23:09 -0000	1.19
> +++ reader.c	24 Sep 2007 14:16:18 -0000
> _at__at_ -1257,7 +1257,7 _at__at_ end_rule()
>      if (!last_was_action && plhs[nrules]->tag)
>      {
>  	for (i = nitems - 1; pitem[i]; --i) continue;
> -	if (pitem[i+1] == 0 || pitem[i+1]->tag != plhs[nrules]->tag)
> +	if (i == nitems - 1 || pitem[i+1]->tag != plhs[nrules]->tag)
>  	    default_action_warning();
>      }
>
> %%%

FWIW, I just verified that the fix works fine, using the same test as
yesterday:

keramida_at_kobe:/home/keramida/tmp/yt$ make
Warning: Object directory not changed from original /home/keramida/tmp/yt
yacc -d -o foo.c foo.y
yacc: w - line 11 of "foo.y", the default action assigns an undefined value to $$
yacc: w - the symbol $$ is undefined
[...]
Received on Mon Sep 24 2007 - 14:03:40 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:18 UTC