From be95a4fe2951374676efc9454ffee8638faaf68d Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 28 Jul 2020 18:51:30 +0200 Subject: scanner: don't crash on strings containing a NUL byte We crash if the input contains a string containing a NUL byte. Reported by Suhwan Song. https://lists.gnu.org/r/bug-bison/2020-07/msg00051.html * src/flex-scanner.h (STRING_FREE): Avoid accidental use of last_string. * src/scan-gram.l: Don't call STRING_FREE without calling STRING_FINISH first. * tests/input.at (Invalid inputs): Check that case. --- THANKS | 1 + src/flex-scanner.h | 10 +++++++++- src/scan-gram.l | 3 ++- tests/input.at | 48 ++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/THANKS b/THANKS index ac073ea6..5c64da3c 100644 --- a/THANKS +++ b/THANKS @@ -185,6 +185,7 @@ Simon Sobisch simonsobisch@web.de Stefano Lattarini stefano.lattarini@gmail.com Stephen Cameron stephenmcameron@gmail.com Steve Murphy murf@parsetree.com +Suhwan Song prada960808@gmail.com Sum Wu sum@geekhouse.org Théophile Ranquet theophile.ranquet@gmail.com Thiru Ramakrishnan thiru.ramakrishnan@gmail.com diff --git a/src/flex-scanner.h b/src/flex-scanner.h index 56ca7ce3..028847fd 100644 --- a/src/flex-scanner.h +++ b/src/flex-scanner.h @@ -112,7 +112,15 @@ static struct obstack obstack_for_string; # define STRING_1GROW(Char) \ obstack_1grow (&obstack_for_string, Char) -# define STRING_FREE() \ +# ifdef NDEBUG +# define STRING_FREE() \ obstack_free (&obstack_for_string, last_string) +# else +# define STRING_FREE() \ + do { \ + obstack_free (&obstack_for_string, last_string); \ + last_string = NULL; \ + } while (0) +#endif #endif diff --git a/src/scan-gram.l b/src/scan-gram.l index f8d85f23..ad2904ce 100644 --- a/src/scan-gram.l +++ b/src/scan-gram.l @@ -403,6 +403,7 @@ eqopt ({sp}=)? { \0 { complain (loc, complaint, _("invalid null character")); + STRING_FINISH (); STRING_FREE (); return GRAM_error; } @@ -599,7 +600,6 @@ eqopt ({sp}=)? STRING_FINISH (); BEGIN INITIAL; loc->start = token_start; - val->CHAR = last_string[0]; if (last_string[0] == '\0') { @@ -615,6 +615,7 @@ eqopt ({sp}=)? } else { + val->CHAR = last_string[0]; STRING_FREE (); return CHAR; } diff --git a/tests/input.at b/tests/input.at index 4da63795..effcd1cc 100644 --- a/tests/input.at +++ b/tests/input.at @@ -1,4 +1,4 @@ -# Checking the Bison scanner. -*- Autotest -*- +# Checking the Bison reader. -*- Autotest -*- # Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. @@ -78,10 +78,13 @@ AT_CLEANUP ## Invalid inputs. ## ## ---------------- ## +# The truly bad guys no human would write, but easily uncovered by +# fuzzers. AT_SETUP([Invalid inputs]) AT_DATA([input.y], [[\000\001\002\377? +"\000" %% ? default: 'a' } @@ -92,16 +95,41 @@ default: 'a' } ]]) AT_PERL_REQUIRE([[-pi -e 's/\\(\d{3})/chr(oct($1))/ge' input.y]]) -AT_BISON_CHECK([input.y], [1], [], +AT_BISON_CHECK([-fcaret input.y], [1], [], [stderr]) + +# Autotest's diffing, when there are NUL bytes, just reports "binary +# files differ". So don't leave NUL bytes. +AT_PERL_CHECK([[-p -e 's{([\0\377])}{sprintf "\\x%02x", ord($1)}ge' stderr]], [], [[input.y:1.1-2: error: invalid characters: '\0\001\002\377?' -input.y:3.1: error: invalid character: '?' -input.y:4.14: error: invalid character: '}' -input.y:5.1: error: invalid character: '%' -input.y:5.2: error: invalid character: '&' -input.y:6.1-17: error: invalid directive: '%a-does-not-exist' -input.y:7.1: error: invalid character: '%' -input.y:7.2: error: invalid character: '-' -input.y:8.1-9.0: error: missing '%}' at end of file + 1 | \x00\xff? + | ^~ +input.y:2.2: error: invalid null character + 2 | "\x00" + | ^ +input.y:4.1: error: invalid character: '?' + 4 | ? + | ^ +input.y:5.14: error: invalid character: '}' + 5 | default: 'a' } + | ^ +input.y:6.1: error: invalid character: '%' + 6 | %& + | ^ +input.y:6.2: error: invalid character: '&' + 6 | %& + | ^ +input.y:7.1-17: error: invalid directive: '%a-does-not-exist' + 7 | %a-does-not-exist + | ^~~~~~~~~~~~~~~~~ +input.y:8.1: error: invalid character: '%' + 8 | %- + | ^ +input.y:8.2: error: invalid character: '-' + 8 | %- + | ^ +input.y:9.1-10.0: error: missing '%}' at end of file + 9 | %{ + | ^~ ]]) AT_CLEANUP -- cgit v1.2.1