diff --git a/lib/libesp32/berry/src/be_lexer.c b/lib/libesp32/berry/src/be_lexer.c index 90031d3f6..4e41bf8f6 100644 --- a/lib/libesp32/berry/src/be_lexer.c +++ b/lib/libesp32/berry/src/be_lexer.c @@ -354,7 +354,9 @@ static btokentype scan_decimal(blexer *lexer) if (has_decimal_dots || is_realexp) { type = TokenReal; } - lexer->buf.s[lexer->buf.len] = '\0'; + /* use save_char to add the null terminator, */ + /* since it handles expanding the buffer if needed. */ + save_char(lexer, '\0'); if (type == TokenReal) { setreal(lexer, be_str2real(lexbuf(lexer), NULL)); } else { @@ -431,7 +433,7 @@ static btokentype scan_string(blexer *lexer); /* forward declaration */ /* scan f-string and transpile it to `format(...)` syntax then feeding the normal lexer and parser */ static void scan_f_string(blexer *lexer) { - char ch; + char ch = '\0'; clear_buf(lexer); scan_string(lexer); /* first scan the entire string in lexer->buf */ diff --git a/lib/libesp32/berry/src/be_strlib.c b/lib/libesp32/berry/src/be_strlib.c index 6743c21e2..2ce560910 100644 --- a/lib/libesp32/berry/src/be_strlib.c +++ b/lib/libesp32/berry/src/be_strlib.c @@ -549,7 +549,7 @@ static const char* skip2dig(const char *s) return s; } -static const char* get_mode(const char *str, char *buf) +static const char* get_mode(const char *str, char *buf, size_t buf_len) { const char *p = str; while (*p && strchr(FLAGES, *p)) { /* skip flags */ @@ -560,8 +560,13 @@ static const char* get_mode(const char *str, char *buf) p = skip2dig(++p); /* skip width (2 digits at most) */ } *(buf++) = '%'; - strncpy(buf, str, p - str + 1); - buf[p - str + 1] = '\0'; + size_t mode_size = p - str + 1; + /* Leave 2 bytes for the leading % and the trailing '\0' */ + if (mode_size > buf_len - 2) { + mode_size = buf_len - 2; + } + strncpy(buf, str, mode_size); + buf[mode_size] = '\0'; return p; } @@ -632,7 +637,7 @@ int be_str_format(bvm *vm) } pushstr(vm, format, p - format); concat2(vm); - p = get_mode(p + 1, mode); + p = get_mode(p + 1, mode, sizeof(mode)); buf[0] = '\0'; if (index > top && *p != '%') { be_raise(vm, "runtime_error", be_pushfstring(vm, diff --git a/lib/libesp32/berry/tests/lexer.be b/lib/libesp32/berry/tests/lexer.be index 2114cab54..db2945bc7 100644 --- a/lib/libesp32/berry/tests/lexer.be +++ b/lib/libesp32/berry/tests/lexer.be @@ -36,6 +36,10 @@ check(45.1e2, 4510) check(45.e2, 4500) check(45.e+2, 4500) +# Ensure pathologically long numbers don't crash the lexer (or cause an buffer overflow) +assert(000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 == 0.0); + + test_source('x = 5; 0...x;', 'unexpected symbol near \'.\'') test_source('x = 5; 0...x;', 'unexpected symbol near \'.\'') test_source('0xg', 'invalid hexadecimal number') diff --git a/lib/libesp32/berry/tests/string.be b/lib/libesp32/berry/tests/string.be index 15b403bb5..448ca5215 100644 --- a/lib/libesp32/berry/tests/string.be +++ b/lib/libesp32/berry/tests/string.be @@ -149,6 +149,9 @@ assert(string.format("%s", false) == 'false') assert(string.format("%q", "\ntest") == '\'\\ntest\'') +# corrupt format string should not crash the VM +string.format("%0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f", 3.5) + # format is now synonym to string.format assert(format == string.format) assert(format("%.1f", 3) == '3.0')