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.
This commit is contained in:
H. Peter Anvin 2008-06-04 11:26:59 -07:00
parent 0eebf799db
commit 88c9e1f88c
4 changed files with 83 additions and 59 deletions

View file

@ -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)

64
quote.c
View file

@ -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;
}
/*

View file

@ -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 */

View file

@ -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... */