summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAkim Demaille <akim.demaille@gmail.com>2021-03-07 10:01:53 +0100
committerAkim Demaille <akim.demaille@gmail.com>2021-03-07 18:41:38 +0100
commitcf899f7a7cc19661861344d2b34cc98f10273cd9 (patch)
treee926c25751837d4587686095efbc049dd08dd1fb /tests
parenta774839ca873d1082f79ba3c4eecc1e242a28ce1 (diff)
downloadbison-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.at127
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