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:
parent
0eebf799db
commit
88c9e1f88c
4 changed files with 83 additions and 59 deletions
59
preproc.c
59
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)
|
||||
|
|
64
quote.c
64
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
2
quote.h
2
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 */
|
||||
|
|
17
stdscan.c
17
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... */
|
||||
|
|
Loading…
Reference in a new issue