summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-06-04 11:26:59 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-06-04 11:26:59 -0700
commit88c9e1f88cd1e67ad4fb2834f3cad6160d5a3fbb (patch)
tree01b0135d5f68e2e9cb80ccdf774d9f687c33fda2
parent0eebf799db452dc1980931bd2f15efde5ecdf28c (diff)
downloadnasm-88c9e1f88cd1e67ad4fb2834f3cad6160d5a3fbb.tar.gz
nasm-88c9e1f88cd1e67ad4fb2834f3cad6160d5a3fbb.tar.bz2
nasm-88c9e1f88cd1e67ad4fb2834f3cad6160d5a3fbb.zip
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.
-rw-r--r--preproc.c59
-rw-r--r--quote.c64
-rw-r--r--quote.h2
-rw-r--r--stdscan.c17
4 files changed, 83 insertions, 59 deletions
diff --git a/preproc.c b/preproc.c
index ac289ca..4052672 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 6bfded3..5a04d36 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 501f735..5f96159 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 0fdd7af..4db1368 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... */