mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 04:13:03 +00:00
yacc: fix push parser
When a pstate is used for multiple successive parses, some state may
leak from one run into the following one. That was introduced in
330552ea49 "yacc.c: push: don't clear
the parser state when accepting/rejecting".
Reported by Ryan <dev@splintermail.com>
https://lists.gnu.org/r/bug-bison/2021-03/msg00000.html
* data/skeletons/yacc.c (yypush_parse): We reusing a pstate from a
previous run, do behave as if it were the first run.
* tests/push.at (Pstate reuse): Check this.
This commit is contained in:
8
NEWS
8
NEWS
@@ -4,11 +4,17 @@ GNU Bison NEWS
|
|||||||
|
|
||||||
** Bug fixes
|
** Bug fixes
|
||||||
|
|
||||||
|
*** Reused Push Parsers
|
||||||
|
|
||||||
|
When a push-parser state structure is used for multiple parses, it was
|
||||||
|
possible for some state to leak from one run into the following one.
|
||||||
|
|
||||||
*** Fix Table Generation
|
*** Fix Table Generation
|
||||||
|
|
||||||
In some very rare conditions, when there are many useless tokens, it was
|
In some very rare conditions, when there are many useless tokens, it was
|
||||||
possible to generate incorrect parsers.
|
possible to generate incorrect parsers.
|
||||||
|
|
||||||
|
|
||||||
* Noteworthy changes in release 3.7.5 (2021-01-24) [stable]
|
* Noteworthy changes in release 3.7.5 (2021-01-24) [stable]
|
||||||
|
|
||||||
** Bug fixes
|
** Bug fixes
|
||||||
@@ -290,7 +296,7 @@ GNU Bison NEWS
|
|||||||
parse errors, since `yynerrs` was also reset. This can be especially
|
parse errors, since `yynerrs` was also reset. This can be especially
|
||||||
troublesome when used in autocompletion, since a parser with error
|
troublesome when used in autocompletion, since a parser with error
|
||||||
recovery would suggest (irrelevant) expected tokens even if there were
|
recovery would suggest (irrelevant) expected tokens even if there were
|
||||||
failure.
|
failures.
|
||||||
|
|
||||||
Now the parser state can be examined when parsing is finished. The parser
|
Now the parser state can be examined when parsing is finished. The parser
|
||||||
state is reset when starting a new parse.
|
state is reset when starting a new parse.
|
||||||
|
|||||||
@@ -1573,14 +1573,16 @@ yyparse (]m4_ifset([b4_parse_param], [b4_formals(b4_parse_param)], [void])[)]])[
|
|||||||
|
|
||||||
switch (yyps->yynew)
|
switch (yyps->yynew)
|
||||||
{
|
{
|
||||||
case 2:
|
|
||||||
yypstate_clear (yyps);
|
|
||||||
goto case_0;
|
|
||||||
|
|
||||||
case_0:
|
|
||||||
case 0:
|
case 0:
|
||||||
yyn = yypact[yystate];
|
yyn = yypact[yystate];
|
||||||
goto yyread_pushed_token;
|
goto yyread_pushed_token;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
yypstate_clear (yyps);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}]])[
|
}]])[
|
||||||
|
|
||||||
YYDPRINTF ((stderr, "Starting parse\n"));
|
YYDPRINTF ((stderr, "Starting parse\n"));
|
||||||
|
|||||||
127
tests/push.at
127
tests/push.at
@@ -25,7 +25,7 @@ AT_BANNER([[Push Parsing Tests]])
|
|||||||
AT_SETUP([[Memory Leak for Early Deletion]])
|
AT_SETUP([[Memory Leak for Early Deletion]])
|
||||||
|
|
||||||
# Requires Valgrind.
|
# Requires Valgrind.
|
||||||
AT_BISON_OPTION_PUSHDEFS
|
AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
|
||||||
AT_DATA_GRAMMAR([[input.y]],
|
AT_DATA_GRAMMAR([[input.y]],
|
||||||
[[
|
[[
|
||||||
%{
|
%{
|
||||||
@@ -144,7 +144,7 @@ AT_CLEANUP
|
|||||||
|
|
||||||
AT_SETUP([[Unsupported Skeletons]])
|
AT_SETUP([[Unsupported Skeletons]])
|
||||||
|
|
||||||
AT_BISON_OPTION_PUSHDEFS
|
AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
|
||||||
AT_DATA([[input.y]],
|
AT_DATA([[input.y]],
|
||||||
[[%glr-parser
|
[[%glr-parser
|
||||||
%define api.push-pull push
|
%define api.push-pull push
|
||||||
@@ -158,3 +158,126 @@ AT_BISON_CHECK([[input.y]], [[1]], [],
|
|||||||
]])
|
]])
|
||||||
|
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
|
|
||||||
|
## -------------- ##
|
||||||
|
## Pstate reuse. ##
|
||||||
|
## -------------- ##
|
||||||
|
|
||||||
|
AT_SETUP([[Pstate reuse]])
|
||||||
|
|
||||||
|
# Make sure that when a single pstate is used for multiple successive
|
||||||
|
# parses, no state from a previous run leaks into the following one.
|
||||||
|
#
|
||||||
|
# See https://lists.gnu.org/r/bug-bison/2021-03/msg00000.html.
|
||||||
|
|
||||||
|
AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
|
||||||
|
AT_DATA_GRAMMAR([[input.y]],
|
||||||
|
[[%code top {
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static char *string_concat (char *a, char *b);
|
||||||
|
]AT_YYERROR_DECLARE[
|
||||||
|
}
|
||||||
|
|
||||||
|
%define parse.trace
|
||||||
|
%define api.pure full
|
||||||
|
%define api.push-pull push
|
||||||
|
%expect 0
|
||||||
|
|
||||||
|
%union {
|
||||||
|
char *sval;
|
||||||
|
};
|
||||||
|
%destructor { free ($$); } <sval>
|
||||||
|
%printer { fprintf (yyo, "%s", $$); } <sval>
|
||||||
|
|
||||||
|
%token <sval> RAW
|
||||||
|
%token EOL
|
||||||
|
|
||||||
|
%type <sval> text
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
line
|
||||||
|
: text EOL { printf ("text: %s\n", $1); free ($1); YYACCEPT; };
|
||||||
|
|
||||||
|
text
|
||||||
|
: RAW { $$ = $1; }
|
||||||
|
| text RAW { $$ = string_concat ($1, $2); }
|
||||||
|
;
|
||||||
|
|
||||||
|
%%
|
||||||
|
]AT_YYERROR_DEFINE[
|
||||||
|
|
||||||
|
static char *
|
||||||
|
string_concat (char *a, char *b)
|
||||||
|
{
|
||||||
|
size_t la = strlen (a);
|
||||||
|
size_t lb = strlen (b);
|
||||||
|
char *res = YY_CAST (char *, malloc (la + lb + 1));
|
||||||
|
strcpy (res, a);
|
||||||
|
strcpy (res + la, b);
|
||||||
|
free (a);
|
||||||
|
free (b);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
push (yypstate *ps, yytoken_kind_t kind, const char *str)
|
||||||
|
{
|
||||||
|
YYSTYPE lval;
|
||||||
|
lval.sval = str ? strdup (str) : YY_NULLPTR;
|
||||||
|
switch (yypush_parse (ps, kind, &lval))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case YYPUSH_MORE:
|
||||||
|
// parsing incomplete, but valid; parser not reset
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
// YYABORT or syntax invalid; parser is reset
|
||||||
|
fprintf (stderr, "invalid input, but no error was thrown\n");
|
||||||
|
return 1;
|
||||||
|
case 2:
|
||||||
|
// memory exhaustion; parser is reset
|
||||||
|
fprintf (stderr, "memory exhaustion during yypush_parse\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
yydebug = !!getenv ("YYDEBUG");
|
||||||
|
yypstate *ps = yypstate_new ();
|
||||||
|
|
||||||
|
#define PUSH(Kind, Val) \
|
||||||
|
do { \
|
||||||
|
if (push (ps, Kind, Val)) \
|
||||||
|
return 1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
PUSH (RAW, "te");
|
||||||
|
PUSH (RAW, "xt");
|
||||||
|
PUSH (EOL, YY_NULLPTR);
|
||||||
|
|
||||||
|
PUSH (RAW, "te");
|
||||||
|
PUSH (RAW, "xt");
|
||||||
|
PUSH (EOL, YY_NULLPTR);
|
||||||
|
|
||||||
|
yypstate_delete (ps);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
]])
|
||||||
|
|
||||||
|
AT_FULL_COMPILE([input])
|
||||||
|
AT_CHECK([./input], 0,
|
||||||
|
[[text: text
|
||||||
|
text: text
|
||||||
|
]])
|
||||||
|
|
||||||
|
AT_BISON_OPTION_POPDEFS
|
||||||
|
AT_CLEANUP
|
||||||
|
|||||||
Reference in New Issue
Block a user