From 88c9e1f88cd1e67ad4fb2834f3cad6160d5a3fbb Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 4 Jun 2008 11:26:59 -0700 Subject: [PATCH] Fix memory management issues with expanded %include Ownership of the filename string was a bit fuzzy, with the result that we were freeing it even though it was retained for use by __FILE__. Clean up a number of other memory management issues with the new quoting code, and change the stdscan implementation to one pass over the string. --- preproc.c | 59 +++++++++++++++++++++++++++++++++------------------------- quote.c | 64 +++++++++++++++++++++++++++++++++++++++------------------------ quote.h | 2 +- stdscan.c | 17 ++++++++--------- 4 files changed, 83 insertions(+), 59 deletions(-) diff --git a/preproc.c b/preproc.c index ac289ca3..40526729 100644 --- a/preproc.c +++ b/preproc.c @@ -1144,11 +1144,18 @@ static int ppscan(void *private_data, struct tokenval *tokval) } if (tline->type == TOK_STRING) { + char bq, *ep; + bool errquote; bool rn_warn; size_t l; - l = nasm_unquote(tline->text); - /* TOKEN_ERRNUM if improperly quoted... */ + bq = tline->text[0]; + l = nasm_unquote(tline->text, &ep); + if (ep[0] != bq || ep[1] != '\0') + errquote = true; + + if (errquote) + return tokval->t_type = TOKEN_ERRNUM; tokval->t_integer = readstrnum(tline->text, l, &rn_warn); if (rn_warn) @@ -1520,8 +1527,8 @@ static bool if_condition(Token * tline, enum preproc_token ct) } /* When comparing strings, need to unquote them first */ if (t->type == TOK_STRING) { - size_t l1 = nasm_unquote(t->text); - size_t l2 = nasm_unquote(tt->text); + size_t l1 = nasm_unquote(t->text, NULL); + size_t l2 = nasm_unquote(tt->text, NULL); if (l1 != l2) { j = false; @@ -2081,20 +2088,21 @@ static int do_directive(Token * tline) return DIRECTIVE_FOUND; case PP_DEPEND: - tline = expand_smacro(tline->next); - skip_white_(tline); - if (!tline || (tline->type != TOK_STRING && - tline->type != TOK_INTERNAL_STRING)) { + t = tline->next = expand_smacro(tline->next); + skip_white_(t); + if (!t || (t->type != TOK_STRING && + t->type != TOK_INTERNAL_STRING)) { error(ERR_NONFATAL, "`%%depend' expects a file name"); + free_tlist(t); free_tlist(origline); return DIRECTIVE_FOUND; /* but we did _something_ */ } - if (tline->next) + if (t->next) error(ERR_WARNING, "trailing garbage after `%%depend' ignored"); - p = tline->text; - if (tline->type != TOK_INTERNAL_STRING) - nasm_unquote(p); + p = t->text; + if (t->type != TOK_INTERNAL_STRING) + nasm_unquote(p, NULL); if (dephead && !in_list(*dephead, p)) { StrList *sl = nasm_malloc(strlen(p)+1+sizeof sl->next); sl->next = NULL; @@ -2102,25 +2110,26 @@ static int do_directive(Token * tline) *deptail = sl; deptail = &sl->next; } + free_tlist(t); free_tlist(origline); return DIRECTIVE_FOUND; case PP_INCLUDE: - tline = expand_smacro(tline->next); - skip_white_(tline); + t = tline->next = expand_smacro(tline->next); + skip_white_(t); - if (!tline || (tline->type != TOK_STRING && - tline->type != TOK_INTERNAL_STRING)) { + if (!t || (t->type != TOK_STRING && + t->type != TOK_INTERNAL_STRING)) { error(ERR_NONFATAL, "`%%include' expects a file name"); free_tlist(origline); return DIRECTIVE_FOUND; /* but we did _something_ */ } - if (tline->next) + if (t->next) error(ERR_WARNING, "trailing garbage after `%%include' ignored"); - p = tline->text; - if (tline->type != TOK_INTERNAL_STRING) - nasm_unquote(p); + p = t->text; + if (t->type != TOK_INTERNAL_STRING) + nasm_unquote(p, NULL); inc = nasm_malloc(sizeof(Include)); inc->next = istk; inc->conds = NULL; @@ -2129,7 +2138,7 @@ static int do_directive(Token * tline) /* -MG given but file not found */ nasm_free(inc); } else { - inc->fname = src_set_fname(p); + inc->fname = src_set_fname(nasm_strdup(p)); inc->lineno = src_set_linnum(0); inc->lineinc = 1; inc->expansion = NULL; @@ -2196,7 +2205,7 @@ static int do_directive(Token * tline) skip_white_(tline); if (tok_type_(tline, TOK_STRING)) { p = tline->text; - nasm_unquote(p); + nasm_unquote(p, NULL); expand_macros_in_string(&p); /* WHY? */ error(ERR_NONFATAL, "%s", p); nasm_free(p); @@ -2681,7 +2690,7 @@ static int do_directive(Token * tline) "trailing garbage after `%%pathsearch' ignored"); p = t->text; if (t->type != TOK_INTERNAL_STRING) - nasm_unquote(p); + nasm_unquote(p, NULL); fp = inc_fopen(p, &xsl, &xsl, true); if (fp) { @@ -2742,7 +2751,7 @@ static int do_directive(Token * tline) macro_start = nasm_malloc(sizeof(*macro_start)); macro_start->next = NULL; - make_tok_num(macro_start, nasm_unquote(t->text)); + make_tok_num(macro_start, nasm_unquote(t->text, NULL)); macro_start->mac = NULL; /* @@ -2831,7 +2840,7 @@ static int do_directive(Token * tline) a2 = evalresult->value; } - len = nasm_unquote(t->text); + len = nasm_unquote(t->text, NULL); if (a2 < 0) a2 = a2+1+len-a1; if (a1+a2 > (int64_t)len) diff --git a/quote.c b/quote.c index 6bfded3e..5a04d36b 100644 --- a/quote.c +++ b/quote.c @@ -183,12 +183,13 @@ static char *emit_utf8(char *q, int32_t v) * * In-place replacement is possible since the unquoted length is always * shorter than or equal to the quoted length. + * + * *ep points to the final quote, or to the null if improperly quoted. */ -size_t nasm_unquote(char *str) +size_t nasm_unquote(char *str, char **ep) { - size_t ln; - char bq, eq; - char *p, *q, *ep; + char bq; + char *p, *q; char *escp = NULL; char c; enum unq_state { @@ -201,33 +202,42 @@ size_t nasm_unquote(char *str) int ndig = 0; int32_t nval = 0; - bq = str[0]; + p = q = str; + + bq = *p++; if (!bq) return 0; - ln = strlen(str); - eq = str[ln-1]; - if ((bq == '\'' || bq == '\"') && bq == eq) { + switch (bq) { + case '\'': + case '\"': /* '...' or "..." string */ - memmove(str, str+1, ln-2); - str[ln-2] = '\0'; - return ln-2; - } - if (bq == '`' || eq == '`') { + while ((c = *p) && c != bq) { + p++; + *q++ = c; + } + *q = '\0'; + break; + + case '`': /* `...` string */ - q = str; - p = str+1; - ep = str+ln-1; state = st_start; - while (p < ep) { - c = *p++; + while ((c = *p)) { + p++; switch (state) { case st_start: - if (c == '\\') + switch (c) { + case '\\': state = st_backslash; - else + break; + case '`': + p--; + goto out; + default: *q++ = c; + break; + } break; case st_backslash: @@ -357,12 +367,18 @@ size_t nasm_unquote(char *str) *q++ = escp[-1]; break; } - *q = '\0'; - return q-str; + out: + break; + + default: + /* Not a quoted string, just return the input... */ + p = q = strchr(str, '\0'); + break; } - /* Otherwise, just return the input... */ - return ln; + if (ep) + *ep = p; + return q-str; } /* diff --git a/quote.h b/quote.h index 501f7350..5f96159e 100644 --- a/quote.h +++ b/quote.h @@ -4,7 +4,7 @@ #include "compiler.h" char *nasm_quote(char *str, size_t len); -size_t nasm_unquote(char *str); +size_t nasm_unquote(char *str, char **endptr); char *nasm_skip_string(char *str); #endif /* NASM_QUOTE_H */ diff --git a/stdscan.c b/stdscan.c index 0fdd7af0..4db13680 100644 --- a/stdscan.c +++ b/stdscan.c @@ -47,7 +47,7 @@ static char *stdscan_copy(char *p, int len) char *text; text = nasm_malloc(len + 1); - strncpy(text, p, len); + memcpy(text, p, len); text[len] = '\0'; if (stdscan_templen >= stdscan_tempsize) { @@ -176,15 +176,14 @@ int stdscan(void *private_data, struct tokenval *tv) } } else if (*stdscan_bufptr == '\'' || *stdscan_bufptr == '"' || *stdscan_bufptr == '`') { - /* a char constant */ - char s; + /* a quoted string */ bool rn_warn; - stdscan_bufptr = nasm_skip_string(tv->t_charptr = stdscan_bufptr); - s = *stdscan_bufptr; - tv->t_inttwo = nasm_unquote(tv->t_charptr); - if (!s) - return tv->t_type = TOKEN_ERRNUM; /* unmatched quotes */ - stdscan_bufptr++; /* skip over final quote */ + char start_quote = *stdscan_bufptr; + tv->t_charptr = stdscan_bufptr; + tv->t_inttwo = nasm_unquote(tv->t_charptr, &stdscan_bufptr); + if (*stdscan_bufptr != start_quote) + return tv->t_type = TOKEN_ERRNUM; + stdscan_bufptr++; /* Skip final quote */ tv->t_integer = readstrnum(tv->t_charptr, tv->t_inttwo, &rn_warn); /* Issue: can't readily check rn_warn, because we might be in a db family context... */ -- 2.11.4.GIT