mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +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:
127
tests/push.at
127
tests/push.at
@@ -25,7 +25,7 @@ AT_BANNER([[Push Parsing Tests]])
|
||||
AT_SETUP([[Memory Leak for Early Deletion]])
|
||||
|
||||
# Requires Valgrind.
|
||||
AT_BISON_OPTION_PUSHDEFS
|
||||
AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
|
||||
AT_DATA_GRAMMAR([[input.y]],
|
||||
[[
|
||||
%{
|
||||
@@ -144,7 +144,7 @@ AT_CLEANUP
|
||||
|
||||
AT_SETUP([[Unsupported Skeletons]])
|
||||
|
||||
AT_BISON_OPTION_PUSHDEFS
|
||||
AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
|
||||
AT_DATA([[input.y]],
|
||||
[[%glr-parser
|
||||
%define api.push-pull push
|
||||
@@ -158,3 +158,126 @@ AT_BISON_CHECK([[input.y]], [[1]], [],
|
||||
]])
|
||||
|
||||
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