Bug: Long brackets with a huge number of '=' causes overflow

A long bracket with too many equal signs can overflow the 'int' used for
the counting and some arithmetic done on the value. Changing the counter
to 'size_t' avoids that. (Because what is counted goes to a buffer, an
overflow in the counter will first raise a buffer-overflow error.)
This commit is contained in:
Roberto Ierusalimschy 2018-12-17 15:36:51 -02:00
parent 063d4e4543
commit 1221e987fe

31
llex.c
View File

@ -244,12 +244,12 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
/* /*
** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return ** reads a sequence '[=*[' or ']=*]', leaving the last bracket.
** its number of '='s; otherwise, return a negative number (-1 iff there ** If sequence is well formed, return its number of '='s + 2; otherwise,
** are no '='s after initial bracket) ** return 1 if there is no '='s or 0 otherwise (an unfinished '[==...').
*/ */
static int skip_sep (LexState *ls) { static size_t skip_sep (LexState *ls) {
int count = 0; size_t count = 0;
int s = ls->current; int s = ls->current;
lua_assert(s == '[' || s == ']'); lua_assert(s == '[' || s == ']');
save_and_next(ls); save_and_next(ls);
@ -257,11 +257,14 @@ static int skip_sep (LexState *ls) {
save_and_next(ls); save_and_next(ls);
count++; count++;
} }
return (ls->current == s) ? count : (-count) - 1; return (ls->current == s) ? count + 2
: (count == 0) ? 1
: 0;
} }
static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { static void read_long_string (LexState *ls, SemInfo *seminfo, size_t sep) {
int line = ls->linenumber; /* initial line (for error message) */ int line = ls->linenumber; /* initial line (for error message) */
save_and_next(ls); /* skip 2nd '[' */ save_and_next(ls); /* skip 2nd '[' */
if (currIsNewline(ls)) /* string starts with a newline? */ if (currIsNewline(ls)) /* string starts with a newline? */
@ -295,8 +298,8 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
} }
} endloop: } endloop:
if (seminfo) if (seminfo)
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + sep,
luaZ_bufflen(ls->buff) - 2*(2 + sep)); luaZ_bufflen(ls->buff) - 2 * sep);
} }
@ -444,9 +447,9 @@ static int llex (LexState *ls, SemInfo *seminfo) {
/* else is a comment */ /* else is a comment */
next(ls); next(ls);
if (ls->current == '[') { /* long comment? */ if (ls->current == '[') { /* long comment? */
int sep = skip_sep(ls); size_t sep = skip_sep(ls);
luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */
if (sep >= 0) { if (sep >= 2) {
read_long_string(ls, NULL, sep); /* skip long comment */ read_long_string(ls, NULL, sep); /* skip long comment */
luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */
break; break;
@ -458,12 +461,12 @@ static int llex (LexState *ls, SemInfo *seminfo) {
break; break;
} }
case '[': { /* long string or simply '[' */ case '[': { /* long string or simply '[' */
int sep = skip_sep(ls); size_t sep = skip_sep(ls);
if (sep >= 0) { if (sep >= 2) {
read_long_string(ls, seminfo, sep); read_long_string(ls, seminfo, sep);
return TK_STRING; return TK_STRING;
} }
else if (sep != -1) /* '[=...' missing second bracket */ else if (sep == 0) /* '[=...' missing second bracket */
lexerror(ls, "invalid long string delimiter", TK_STRING); lexerror(ls, "invalid long string delimiter", TK_STRING);
return '['; return '[';
} }