scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit e8a346f902729546b0d5db1c6bf9f0325fd648c1
parent 332f651c0a71c0225dfb4271cb9cfddacc22c9fd
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Fri, 12 Nov 2021 21:57:31 +0100

cc1: Fix double free() error

The current code was too complex without a good reason. The lexer was not
trying to concatenate consecutive strings, and this work was done in the
expression parser. This was an error because it introduced complexity due
to the memory allocation needed to concatenate the strings, and the only
reason to do this was to avoid moving lineno variable that could produce
more difficult to read error messages because they could be moved to
different lines. That problem must be solved in a different way, where
the variable line that is used in error reporting must be updated only
when the beginning of a new token is detected.

Diffstat:
Msrc/cmd/cc/cc1/expr.c | 33+++------------------------------
Msrc/cmd/cc/cc1/lex.c | 78++++++++++++++++++++++++++++++++++++++++++------------------------------------
2 files changed, 45 insertions(+), 66 deletions(-)

diff --git a/src/cmd/cc/cc1/expr.c b/src/cmd/cc/cc1/expr.c @@ -589,34 +589,6 @@ notdefined(Symbol *sym) return install(sym->ns, yylval.sym); } -static Symbol * -adjstrings(Symbol *sym) -{ - char *s, *t; - size_t len, n; - Type *tp; - - tp = sym->type; - s = sym->u.s; - for (len = strlen(s);; len += n) { - next(); - if (yytoken != STRING) - break; - t = yylval.sym->u.s; - n = strlen(t); - s = xrealloc(s, len + n + 1); - memcpy(s+len, t, n); - s[len + n] = '\0'; - killsym(yylval.sym); - } - ++len; - if (tp->n.elem != len) { - sym->type = mktype(chartype, ARY, len, NULL); - sym->u.s = s; - } - return sym; -} - /************************************************************* * grammar functions * *************************************************************/ @@ -630,11 +602,12 @@ primary(void) sym = yylval.sym; switch (yytoken) { case STRING: - np = constnode(adjstrings(sym)); + np = constnode(sym); sym->flags |= SHASINIT; emit(ODECL, sym); emit(OINIT, np); - return varnode(sym); + np = varnode(sym); + break; case BUILTIN: fun = sym->u.fun; next(); diff --git a/src/cmd/cc/cc1/lex.c b/src/cmd/cc/cc1/lex.c @@ -544,6 +544,42 @@ character(void) } /* + * skip all the spaces until the next token. When we are in + * CPPMODE \n is not considered a whitespace + */ +static int +skipspaces(void) +{ + int c; + + for (;;) { + switch (c = *input->p) { + case '\n': + if (lexmode == CPPMODE) + goto return_byte; + ++input->p; + case '\0': + if (!moreinput()) + return EOF; + break; + case ' ': + case '\t': + case '\v': + case '\r': + case '\f': + ++input->p; + break; + default: + goto return_byte; + } + } + +return_byte: + input->begin = input->p; + return c; +} + +/* * string() parses a constant string, and convert all the * escape sequences into single characters. This behaviour * is correct except when we parse a #define, where we want @@ -559,6 +595,8 @@ string(void) *bp++ = '"'; esc = 0; + +repeat: for (++input->p; ; ++input->p) { c = *input->p; @@ -593,6 +631,10 @@ string(void) } input->begin = ++input->p; + + if (skipspaces() == '"') + goto repeat; + *bp = '\0'; yylen = bp - yytext + 1; @@ -756,42 +798,6 @@ operator(void) /* TODO: Ensure that namespace is NS_IDEN after a recovery */ -/* - * skip all the spaces until the next token. When we are in - * CPPMODE \n is not considered a whitespace - */ -static int -skipspaces(void) -{ - int c; - - for (;;) { - switch (c = *input->p) { - case '\n': - if (lexmode == CPPMODE) - goto return_byte; - ++input->p; - case '\0': - if (!moreinput()) - return EOF; - break; - case ' ': - case '\t': - case '\v': - case '\r': - case '\f': - ++input->p; - break; - default: - goto return_byte; - } - } - -return_byte: - input->begin = input->p; - return c; -} - int next(void) {