diff options
author | Akim Demaille <akim.demaille@gmail.com> | 2021-03-07 10:01:53 +0100 |
---|---|---|
committer | Akim Demaille <akim.demaille@gmail.com> | 2021-03-07 18:41:38 +0100 |
commit | cf899f7a7cc19661861344d2b34cc98f10273cd9 (patch) | |
tree | e926c25751837d4587686095efbc049dd08dd1fb /tests | |
parent | a774839ca873d1082f79ba3c4eecc1e242a28ce1 (diff) | |
download | bison-cf899f7a7cc19661861344d2b34cc98f10273cd9.tar.gz |
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
330552ea499ca474f65967160e9d4e50265f9631 "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.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/push.at | 127 |
1 files changed, 125 insertions, 2 deletions
diff --git a/tests/push.at b/tests/push.at index cd3e113e..0cfb346e 100644 --- a/tests/push.at +++ b/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 |