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.
This commit is contained in:
Akim Demaille
2020-07-28 18:51:30 +02:00
parent 6accee7716
commit be95a4fe29
4 changed files with 50 additions and 12 deletions

1
THANKS
View File

@@ -185,6 +185,7 @@ Simon Sobisch simonsobisch@web.de
Stefano Lattarini stefano.lattarini@gmail.com Stefano Lattarini stefano.lattarini@gmail.com
Stephen Cameron stephenmcameron@gmail.com Stephen Cameron stephenmcameron@gmail.com
Steve Murphy murf@parsetree.com Steve Murphy murf@parsetree.com
Suhwan Song prada960808@gmail.com
Sum Wu sum@geekhouse.org Sum Wu sum@geekhouse.org
Théophile Ranquet theophile.ranquet@gmail.com Théophile Ranquet theophile.ranquet@gmail.com
Thiru Ramakrishnan thiru.ramakrishnan@gmail.com Thiru Ramakrishnan thiru.ramakrishnan@gmail.com

View File

@@ -112,7 +112,15 @@ static struct obstack obstack_for_string;
# define STRING_1GROW(Char) \ # define STRING_1GROW(Char) \
obstack_1grow (&obstack_for_string, Char) obstack_1grow (&obstack_for_string, Char)
# define STRING_FREE() \ # ifdef NDEBUG
# define STRING_FREE() \
obstack_free (&obstack_for_string, last_string) 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 #endif

View File

@@ -403,6 +403,7 @@ eqopt ({sp}=)?
{ {
\0 { \0 {
complain (loc, complaint, _("invalid null character")); complain (loc, complaint, _("invalid null character"));
STRING_FINISH ();
STRING_FREE (); STRING_FREE ();
return GRAM_error; return GRAM_error;
} }
@@ -599,7 +600,6 @@ eqopt ({sp}=)?
STRING_FINISH (); STRING_FINISH ();
BEGIN INITIAL; BEGIN INITIAL;
loc->start = token_start; loc->start = token_start;
val->CHAR = last_string[0];
if (last_string[0] == '\0') if (last_string[0] == '\0')
{ {
@@ -615,6 +615,7 @@ eqopt ({sp}=)?
} }
else else
{ {
val->CHAR = last_string[0];
STRING_FREE (); STRING_FREE ();
return CHAR; return CHAR;
} }

View File

@@ -1,4 +1,4 @@
# Checking the Bison scanner. -*- Autotest -*- # Checking the Bison reader. -*- Autotest -*-
# Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. # Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc.
@@ -78,10 +78,13 @@ AT_CLEANUP
## Invalid inputs. ## ## Invalid inputs. ##
## ---------------- ## ## ---------------- ##
# The truly bad guys no human would write, but easily uncovered by
# fuzzers.
AT_SETUP([Invalid inputs]) AT_SETUP([Invalid inputs])
AT_DATA([input.y], AT_DATA([input.y],
[[\000\001\002\377? [[\000\001\002\377?
"\000"
%% %%
? ?
default: 'a' } default: 'a' }
@@ -92,16 +95,41 @@ default: 'a' }
]]) ]])
AT_PERL_REQUIRE([[-pi -e 's/\\(\d{3})/chr(oct($1))/ge' input.y]]) 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:1.1-2: error: invalid characters: '\0\001\002\377?'
input.y:3.1: error: invalid character: '?' 1 | \x00\xff?
input.y:4.14: error: invalid character: '}' | ^~
input.y:5.1: error: invalid character: '%' input.y:2.2: error: invalid null character
input.y:5.2: error: invalid character: '&' 2 | "\x00"
input.y:6.1-17: error: invalid directive: '%a-does-not-exist' | ^
input.y:7.1: error: invalid character: '%' input.y:4.1: error: invalid character: '?'
input.y:7.2: error: invalid character: '-' 4 | ?
input.y:8.1-9.0: error: missing '%}' at end of file | ^
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 AT_CLEANUP