From 1c21a53e4ed03371df5d9f16359545862bb4820e Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin (Intel)" Date: Fri, 9 Aug 2019 02:34:21 -0700 Subject: [PATCH] preproc: fix parsing of single-line macro arguments, cleanups The single-line macro argument parsing was completely broken as a comma would not be recognized as an argument separator. In the process of fixing this, make a fair bit of code cleanups. Note: reverse tokens for smacro->expansion doesn't actually make any sense anymore, might reconsider that. This checkin also removes the distinction between "magic" and plain smacros; the only difference is which specific expand method is being invoked. Finally, extend the allocating-string functions such that *all* the allocating string functions support querying the length of the string a posteori. Signed-off-by: H. Peter Anvin (Intel) --- asm/preproc.c | 485 +++++++++++++++++++++++++++------------------ include/nasmlib.h | 18 +- nasmlib/alloc.c | 18 +- nasmlib/alloc.h | 2 + nasmlib/asprintf.c | 14 +- nasmlib/strlist.c | 2 +- 6 files changed, 332 insertions(+), 207 deletions(-) diff --git a/asm/preproc.c b/asm/preproc.c index 4a01f979..7a5d11fe 100644 --- a/asm/preproc.c +++ b/asm/preproc.c @@ -96,10 +96,10 @@ typedef struct Cond Cond; */ /* - * Function call for a magic smacro + * Function call tp obtain the expansion of an smacro */ -typedef Token *(*MagicSMacro)(const SMacro *s, Token **params, - unsigned int nparams, bool *free_expansion); +typedef Token *(*ExpandSMacro)(const SMacro *s, Token **params, + unsigned int nparams); /* * Store the definition of a single-line macro. @@ -108,8 +108,8 @@ struct SMacro { SMacro *next; /* MUST BE FIRST - see free_smacro() */ char *name; Token *expansion; - MagicSMacro magic; - intorptr magicpvt; + ExpandSMacro expand; + intorptr expandpvt; bool *eval_param; unsigned int nparam; bool casesense; @@ -605,6 +605,53 @@ static void free_llist(Line * list) } } +/* + * Free an array of linked lists of tokens + */ +static void free_tlist_array(Token **array, size_t nlists) +{ + Token **listp = array; + + while (nlists--) + free_tlist(*listp++); + + nasm_free(array); +} + +/* + * Duplicate a linked list of tokens. + */ +static Token *dup_tlist(const Token *list, Token ***tailp) +{ + Token *newlist = NULL; + Token **tailpp = &newlist; + const Token *t; + + list_for_each(t, list) { + Token *nt; + *tailpp = nt = dup_Token(NULL, t); + tailpp = &nt->next; + } + + if (tailp) + *tailp = tailpp; + + return newlist; +} + +/* + * Duplicate a linked list of tokens in reverse order + */ +static Token *dup_tlist_reverse(const Token *list, Token *tail) +{ + const Token *t; + + list_for_each(t, list) + tail = dup_Token(tail, t); + + return tail; +} + /* * Free an MMacro */ @@ -779,7 +826,6 @@ static char *line_from_stdmac(void) stdmacpos = *stdmacnext++; } else if (do_predef) { Line *pd, *l; - Token *head, **tail, *t; /* * Nasty hack: here we push the contents of @@ -789,16 +835,9 @@ static char *line_from_stdmac(void) * features. */ list_for_each(pd, predef) { - head = NULL; - tail = &head; - list_for_each(t, pd->first) { - *tail = new_Token(NULL, t->type, t->text, 0); - tail = &(*tail)->next; - } - l = nasm_malloc(sizeof(Line)); l->next = istk->expansion; - l->first = head; + l->first = dup_tlist(pd->first, NULL); l->finishes = NULL; istk->expansion = l; @@ -2022,6 +2061,19 @@ fail: return -1; } +/* + * Default smacro expansion routine: just returns a copy of the + * expansion list. + */ +static Token * +smacro_expand_default(const SMacro *s, Token **params, unsigned int nparams) +{ + (void)params; + (void)nparams; + + return dup_tlist(s->expansion, NULL); +} + /* * Common code for defining an smacro */ @@ -2060,6 +2112,7 @@ static SMacro *define_smacro(Context *ctx, const char *mname, smac->casesense = casesense; smac->nparam = nparam; smac->expansion = expansion; + smac->expand = smacro_expand_default; return smac; } @@ -3908,10 +3961,10 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) tm = mac->params[(fst + mac->rotate) % mac->nparam]; if (!tm) goto err; - head = new_Token(NULL, tm->type, tm->text, 0); + head = dup_Token(NULL, tm); tt = &head->next, tm = tm->next; while (tok_isnt_(tm, ",")) { - t = new_Token(NULL, tm->type, tm->text, 0); + t = dup_Token(NULL, tm); *tt = t, tt = &t->next, tm = tm->next; } @@ -3922,7 +3975,7 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) j = (i + mac->rotate) % mac->nparam; tm = mac->params[j]; while (tok_isnt_(tm, ",")) { - t = new_Token(NULL, tm->type, tm->text, 0); + t = dup_Token(NULL, tm); *tt = t, tt = &t->next, tm = tm->next; } } @@ -3933,7 +3986,7 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) j = (i + mac->rotate) % mac->nparam; tm = mac->params[j]; while (tok_isnt_(tm, ",")) { - t = new_Token(NULL, tm->type, tm->text, 0); + t = dup_Token(NULL, tm); *tt = t, tt = &t->next, tm = tm->next; } } @@ -4055,7 +4108,7 @@ static Token *expand_mmac_params(Token * tline) } if (tt) { for (i = 0; i < mac->paramlen[n]; i++) { - *tail = new_Token(NULL, tt->type, tt->text, 0); + *tail = dup_Token(NULL, tt); tail = &(*tail)->next; tt = tt->next; } @@ -4157,10 +4210,9 @@ static bool expand_one_smacro(Token ***tpp) Token *tline = **tpp; Token *mstart = **tpp; SMacro *head, *m; - unsigned int nparam, i; - Token *expansion; - Token *t; - bool free_expansion; + unsigned int i; + Token *t, *tup, *ttail; + unsigned int nparam = 0; if (!tline) return false; /* Empty line, nothing to do */ @@ -4214,8 +4266,8 @@ static bool expand_one_smacro(Token ***tpp) * substitute for the parameters when we expand. What a * pain. */ - Token **pep; - int paren; + Token **phead, **pep; + int paren = 1; int white = 0; int brackets = 0; bool bracketed = false; @@ -4237,113 +4289,131 @@ static bool expand_one_smacro(Token ***tpp) paren = 1; nparam = 0; - params = nasm_malloc(sparam * sizeof *params); - params[0] = NULL; - pep = ¶ms[0]; + nasm_newn(params, sparam); + phead = pep = ¶ms[0]; + *pep = NULL; - while (true) { - bool skip = false; + while (paren) { + bool skip; char ch; - if (!tline->next) { - nasm_nonfatal("macro call expects terminating `)'"); - break; - } tline = tline->next; - ch = (tline->type == TOK_OTHER && !tline->text[1]) - ? tline->text[0] : 0; - - if (!brackets) { - if (tline->type == TOK_WHITESPACE) { - if (params[nparam]) { - /* Keep interior whitespace */ - white++; - } - skip = true; - } - - switch (ch) { - case ',': - if (!paren) { - if (++nparam >= sparam) { - sparam += PARAM_DELTA; - params = nasm_realloc(params, sparam * sizeof *params); - } - params[nparam] = NULL; - pep = ¶ms[nparam]; - white = 0; - bracketed = false; - } - break; - - case '{': - brackets++; - bracketed = skip = !params[nparam]; - break; - - case '(': - paren++; - break; - - case ')': - paren--; - break; - - default: - break; /* Just advance to the next token */ - } - } else { - if (ch == '}') - brackets--; - - if (brackets == 0) - skip = bracketed; + if (!tline) { + nasm_nonfatal("macro call expects terminating `)'"); + goto not_a_macro; } - if (!paren) - break; /* We are done */ + ch = 0; + skip = false; + + switch (tline->type) { + case TOK_OTHER: + if (!tline->text[1]) + ch = tline->text[0]; + break; + + case TOK_WHITESPACE: + if (brackets || *phead) + white++; /* Keep interior whitespace */ + skip = true; + break; + + default: + break; + } + + switch (ch) { + case ',': + if (!brackets) { + if (++nparam >= sparam) { + sparam += PARAM_DELTA; + params = nasm_realloc(params, sparam * sizeof *params); + } + pep = ¶ms[nparam]; + *pep = NULL; + bracketed = false; + skip = true; + } + break; + + case '{': + if (!bracketed) { + bracketed = !*phead; + skip = true; + } + brackets++; + break; + + case '}': + if (brackets > 0) { + if (!--brackets) + skip = bracketed; + } + break; + + case '(': + if (!brackets) + paren++; + break; + + case ')': + if (!brackets) { + paren--; + if (!paren) { + skip = true; + if (nparam > 0 || *phead) { + /* Count the final argument unless just () */ + nparam++; + } + } + } + break; + + default: + break; /* Normal token */ + } if (!skip) { Token *t; - if (bracketed && !brackets) - bad_bracket = true; + bad_bracket |= bracketed && !brackets; if (white) { - t = new_Token(NULL, TOK_WHITESPACE, NULL, 0); - *pep = t; + *pep = t = new_Token(NULL, TOK_WHITESPACE, NULL, 0); pep = &t->next; + white = 0; } - - t = new_Token(NULL, tline->type, tline->text, 0); - *pep = t; + *pep = t = dup_Token(NULL, tline); pep = &t->next; white = 0; } } - nparam++; /* Count the last parameter */ - if (bad_bracket) - nasm_nonfatal("braces do not enclose all of macro parameter"); + /* + * Look for a macro matching in both name and parameter count. + * We already know any matches cannot be anywhere before the + * current position of "m", so there is no reason to + * backtrack. + */ + while (1) { + if (!m) { + /*! + *!macro-params-single [on] single-line macro calls with wrong parameter count + *! warns about \i{single-line macros} being invoked + *! with the wrong number of parameters. + */ + nasm_warn(WARN_MACRO_PARAMS_SINGLE, + "single-line macro `%s' exists, " + "but not taking %d parameter%s", + mname, nparam, (nparam == 1) ? "" : "s"); + goto not_a_macro; + } + + if (m->nparam == nparam && !mstrcmp(m->name, mname, m->casesense)) + break; /* It's good */ - /* Look for a macro matching in both name and parameter count */ - while (m && (m->nparam != nparam || - mstrcmp(m->name, mname, m->casesense))) m = m->next; - - if (!m) { - /*! - *!macro-params [on] macro calls with wrong parameter count - *! covers warnings about \i{multi-line macros} being invoked - *! with the wrong number of parameters. See \k{mlmacover} for an - *! example of why you might want to disable this warning. - */ - nasm_warn(WARN_MACRO_PARAMS, - "macro `%s' exists, " - "but not taking %d parameters", - mname, nparam); - goto not_a_macro; } } @@ -4353,89 +4423,110 @@ static bool expand_one_smacro(Token ***tpp) /* Expand each parameter */ m->in_progress = true; - for (i = 0; i < nparam; i++) { - params[i] = expand_smacro_noreset(params[i]); + if (m->eval_param) { + for (i = 0; i < nparam; i++) { + if (m->eval_param[i]) { + /* Evaluate this parameter as a number */ + struct ppscan pps; + struct tokenval tokval; + expr *evalresult; + Token *eval_param; - if (m->eval_param && m->eval_param[i]) { - /* Evaluate this parameter as a number */ - struct ppscan pps; - struct tokenval tokval; - expr *evalresult; + pps.tptr = eval_param = expand_smacro_noreset(params[i]); + pps.ntokens = -1; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL); - pps.tptr = params[i]; - pps.ntokens = -1; - tokval.t_type = TOKEN_INVALID; - evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL); + free_tlist(eval_param); + params[i] = NULL; - if (!evalresult) { - /* Nothing meaningful to do */ - } else if (tokval.t_type) { - nasm_nonfatal("invalid expression in parameter %d of macro `%s'", i, m->name); - } else if (!is_simple(evalresult)) { - nasm_nonfatal("non-constant expression in parameter %d of macro `%s'", i, m->name); - } else { - free_tlist(params[i]); - params[i] = make_tok_num(reloc_value(evalresult)); + if (!evalresult) { + /* Nothing meaningful to do */ + } else if (tokval.t_type) { + nasm_nonfatal("invalid expression in parameter %d of macro `%s'", i, m->name); + } else if (!is_simple(evalresult)) { + nasm_nonfatal("non-constant expression in parameter %d of macro `%s'", i, m->name); + } else { + params[i] = make_tok_num(reloc_value(evalresult)); + } } } - - /* Put tokens in reverse order like the expansion list */ - params[i] = reverse_tokens(params[i]); } t = tline; tline = tline->next; /* Remove the macro call from the input */ t->next = NULL; - if (unlikely(m->magic)) { - expansion = m->magic(m, params, nparam, &free_expansion); - } else { - expansion = m->expansion; - free_expansion = false; - } + /* Note: we own the expansion this returns. */ + t = m->expand(m, params, nparam); - list_for_each(t, expansion) { - Token *ttt, **tlinep; - const char *qname; + tup = NULL; + ttail = NULL; /* Pointer to the last token of the expansion */ + while (t) { + enum pp_token_type type = t->type; + Token *tnext = t->next; + Token **tp; + + switch (type) { + case TOK_PREPROC_Q: + case TOK_PREPROC_QQ: + t->type = TOK_ID; + nasm_free(t->text); + t->text = nasm_strdup(type == TOK_PREPROC_QQ ? m->name : mname); + t->len = nasm_last_string_len(); + t->next = tline; + break; - switch (t->type) { case TOK_ID: case TOK_PREPROC_ID: - tline = dup_Token(tline, t); - tlinep = &tline; - expand_one_smacro(&tlinep); - break; - case TOK_PREPROC_Q: - qname = mname; - goto q_qq; - case TOK_PREPROC_QQ: - qname = m->name; - goto q_qq; - q_qq: - tline = new_Token(tline, TOK_ID, qname, 0); + /* + * Chain this into the target line *before* expanding, + * that way we pick up any arguments to the new macro call, + * if applicable. + */ + t->next = tline; + tp = &t; + expand_one_smacro(&tp); + if (t == tline) + t = NULL; /* Null expansion */ break; + default: if (is_smac_param(t->type)) { - list_for_each(ttt, params[smac_nparam(t->type)]) { - tline = dup_Token(tline, ttt); - } + unsigned int param = smac_nparam(t->type); + nasm_assert(!tup && param < nparam); + delete_Token(t); + t = NULL; + tup = tnext; + tnext = dup_tlist_reverse(params[param], NULL); } else { - tline = dup_Token(tline, t); + t->next = tline; } - break; + } + + if (t) { + tline = t; + if (!ttail) + ttail = t; + } + + if (tnext) { + t = tnext; + } else { + t = tup; + tup = NULL; } } **tpp = tline; - - if (free_expansion) - free_tlist(expansion); + if (ttail) + *tpp = &ttail->next; m->in_progress = false; /* Don't do this until after expansion or we will clobber mname */ free_tlist(mstart); - nasm_free(params); + free_tlist_array(params, nparam); return true; /* @@ -4443,9 +4534,8 @@ static bool expand_one_smacro(Token ***tpp) * and then advance to the next input token. */ not_a_macro: - if (params) - nasm_free(params); *tpp = &mstart->next; + free_tlist_array(params, nparam); return false; } @@ -4466,6 +4556,7 @@ static Token *expand_smacro_noreset(Token * tline) { Token *t, **tail, *thead; Token *org_tline = tline; + bool expanded; /* * Trick: we should avoid changing the start token pointer since it can @@ -4480,9 +4571,16 @@ static Token *expand_smacro_noreset(Token * tline) org_tline->text = NULL; } - thead = tline; - while (1) { + /* + * Pretend that we always end up doing expansion on the first pass; + * that way %+ get processed. However, if we process %+ before the + * first pass, we end up with things like MACRO %+ TAIL trying to + * look up the macro "MACROTAIL", which we don't want. + */ + expanded = true; + thead = tline; + while (true) { static const struct tokseq_match tmatch[] = { { PP_CONCAT_MASK(TOK_ID) | @@ -4492,10 +4590,8 @@ static Token *expand_smacro_noreset(Token * tline) PP_CONCAT_MASK(TOK_NUMBER) /* tail */ } }; - bool expanded = false; tail = &thead; - while ((t = *tail)) { /* main token loop */ expanded |= expand_one_smacro(&tail); @@ -4514,6 +4610,8 @@ static Token *expand_smacro_noreset(Token * tline) * before and after them (without white spaces in between). */ paste_tokens(&thead, tmatch, ARRAY_SIZE(tmatch), true); + + expanded = false; } if (org_tline) { @@ -4523,9 +4621,11 @@ static Token *expand_smacro_noreset(Token * tline) thead->text = NULL; delete_Token(thead); } else { - /* the expression expanded to empty line; - we can't return NULL for some reasons - we just set the line to a single WHITESPACE token. */ + /* + * The expression expanded to empty line; + * we can't return NULL because of the "trick" above. + * Just set the line to a single WHITESPACE token. + */ memset(org_tline, 0, sizeof(*org_tline)); org_tline->text = NULL; org_tline->type = TOK_WHITESPACE; @@ -4689,10 +4789,15 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array) /* * After all that, we didn't find one with the right number of * parameters. Issue a warning, and fail to expand the macro. + *! + *!macro-params-multi [on] multi-line macro calls with wrong parameter count + *! warns about \i{multi-line macros} being invoked + *! with the wrong number of parameters. See \k{mlmacover} for an + *! example of why you might want to disable this warning. */ - nasm_warn(WARN_MACRO_PARAMS, - "macro `%s' exists, but not taking %d parameters", - tline->text, nparam); + nasm_warn(WARN_MACRO_PARAMS_MULTI, + "multi-line macro `%s' exists, but not taking %d parameter%s", + tline->text, nparam, (nparam == 1) ? "" : "s"); nasm_free(params); return NULL; } @@ -4973,41 +5078,38 @@ static void pp_verror(errflags severity, const char *fmt, va_list arg) } } -static Token *stdmac_file(const SMacro *s, Token **params, - unsigned int nparams, bool *free_expansion) +static Token * +stdmac_file(const SMacro *s, Token **params, unsigned int nparams) { (void)s; (void)params; (void)nparams; - *free_expansion = true; return make_tok_qstr(src_get_fname()); } -static Token *stdmac_line(const SMacro *s, Token **params, - unsigned int nparams, bool *free_expansion) +static Token * +stdmac_line(const SMacro *s, Token **params, unsigned int nparams) { (void)s; (void)params; (void)nparams; - *free_expansion = true; return make_tok_num(src_get_linnum()); } -static Token *stdmac_bits(const SMacro *s, Token **params, - unsigned int nparams, bool *free_expansion) +static Token * +stdmac_bits(const SMacro *s, Token **params, unsigned int nparams) { (void)s; (void)params; (void)nparams; - *free_expansion = true; return make_tok_num(globalbits); } -static Token *stdmac_ptr(const SMacro *s, Token **params, - unsigned int nparams, bool *free_expansion) +static Token * +stdmac_ptr(const SMacro *s, Token **params, unsigned int nparams) { const Token *t; static const Token ptr_word = { NULL, "word", 4, TOK_ID }; @@ -5032,15 +5134,14 @@ static Token *stdmac_ptr(const SMacro *s, Token **params, panic(); } - *free_expansion = false; - return (Token *)t; + return dup_Token(NULL, t); } /* Add magic standard macros */ struct magic_macros { const char *name; int nparams; - MagicSMacro func; + ExpandSMacro func; }; static const struct magic_macros magic_macros[] = { @@ -5058,7 +5159,7 @@ static void pp_add_magic_stdmac(void) for (m = magic_macros; m->name; m++) { s = define_smacro(NULL, m->name, true, m->nparams, NULL); - s->magic = m->func; + s->expand = m->func; } } @@ -5179,7 +5280,7 @@ static Token *pp_tokline(void) list_for_each(t, l->first) { if (t->text || t->type == TOK_WHITESPACE) { - tt = *tail = new_Token(NULL, t->type, t->text, 0); + tt = *tail = dup_Token(NULL, t); tail = &tt->next; } } diff --git a/include/nasmlib.h b/include/nasmlib.h index b8666e67..eb3a637d 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -87,10 +87,22 @@ char * safe_alloc nasm_vasprintf(const char *fmt, va_list ap); void * safe_alloc printf_func(2, 3) nasm_axprintf(size_t extra, const char *fmt, ...); void * safe_alloc nasm_vaxprintf(size_t extra, const char *fmt, va_list ap); -extern size_t _nasm_aprintf_size; -static inline size_t nasm_aprintf_size(void) +/* + * nasm_last_string_len() returns the length of the last string allocated + * by [v]asprintf, nasm_strdup, nasm_strcat, or nasm_strcatn. + * + * nasm_last_string_size() returns the equivalent size including the + * final NUL. + */ +static inline size_t nasm_last_string_len(void) { - return _nasm_aprintf_size; + extern size_t _nasm_last_string_size; + return _nasm_last_string_size - 1; +} +static inline size_t nasm_last_string_size(void) +{ + extern size_t _nasm_last_string_size; + return _nasm_last_string_size; } /* Assert the argument is a pointer without evaluating it */ diff --git a/nasmlib/alloc.c b/nasmlib/alloc.c index ad2cff3d..4e0ff9fe 100644 --- a/nasmlib/alloc.c +++ b/nasmlib/alloc.c @@ -40,6 +40,8 @@ #include "error.h" #include "alloc.h" +size_t _nasm_last_string_size; + no_return nasm_alloc_failed(void) { /* If nasm_fatal() gets us back here, then croak hard */ @@ -90,8 +92,9 @@ void nasm_free(void *q) char *nasm_strdup(const char *s) { char *p; - size_t size = strlen(s) + 1; + const size_t size = strlen(s) + 1; + _nasm_last_string_size = size; p = nasm_malloc(size); return memcpy(p, s, size); } @@ -101,6 +104,7 @@ char *nasm_strndup(const char *s, size_t len) char *p; len = strnlen(s, len); + _nasm_last_string_size = len + 1; p = nasm_malloc(len+1); p[len] = '\0'; return memcpy(p, s, len); @@ -109,11 +113,13 @@ char *nasm_strndup(const char *s, size_t len) char *nasm_strcat(const char *one, const char *two) { char *rslt; - size_t l1 = strlen(one); - size_t l2 = strlen(two); - rslt = nasm_malloc(l1 + l2 + 1); + const size_t l1 = strlen(one); + const size_t s2 = strlen(two) + 1; + + _nasm_last_string_size = l1 + s2; + rslt = nasm_malloc(l1 + s2); memcpy(rslt, one, l1); - memcpy(rslt + l1, two, l2+1); + memcpy(rslt + l1, two, s2); return rslt; } @@ -150,6 +156,8 @@ char *nasm_strcatn(const char *str1, ...) } va_end(ap); + _nasm_last_string_size = s; + q = rslt = nasm_malloc(s); p = str1; diff --git a/nasmlib/alloc.h b/nasmlib/alloc.h index c599d213..1b896585 100644 --- a/nasmlib/alloc.h +++ b/nasmlib/alloc.h @@ -45,4 +45,6 @@ static inline void *validate_ptr(void *p) return p; } +extern size_t _nasm_last_string_size; + #endif /* NASMLIB_ALLOC_H */ diff --git a/nasmlib/asprintf.c b/nasmlib/asprintf.c index be88d491..0b8e49d8 100644 --- a/nasmlib/asprintf.c +++ b/nasmlib/asprintf.c @@ -38,16 +38,15 @@ /* * nasm_[v]asprintf() are variants of the semi-standard [v]asprintf() * functions, except that we return the pointer instead of a count. - * The size of the string (including the final NUL!) is available - * by calling nasm_aprintf_size() afterwards. + * The length of the string (with or without the final NUL) is available + * by calling nasm_last_string_{len,size}() afterwards. * * nasm_[v]axprintf() are similar, but allocates a user-defined amount * of storage before the string, and returns a pointer to the - * allocated buffer. + * allocated buffer. The size of that area is not included in the value + * returned by nasm_last_string_size(). */ -size_t _nasm_aprintf_size; - void *nasm_vaxprintf(size_t extra, const char *fmt, va_list ap) { char *strp; @@ -55,9 +54,12 @@ void *nasm_vaxprintf(size_t extra, const char *fmt, va_list ap) size_t bytes; va_copy(xap, ap); - _nasm_aprintf_size = bytes = vsnprintf(NULL, 0, fmt, xap) + 1; + bytes = vsnprintf(NULL, 0, fmt, xap) + 1; + _nasm_last_string_size = bytes; va_end(xap); + strp = nasm_malloc(extra+bytes); + memset(strp, 0, extra); vsnprintf(strp+extra, bytes, fmt, ap); return strp; } diff --git a/nasmlib/strlist.c b/nasmlib/strlist.c index a0687cce..db5a09ab 100644 --- a/nasmlib/strlist.c +++ b/nasmlib/strlist.c @@ -109,7 +109,7 @@ strlist_vprintf(struct strlist *list, const char *fmt, va_list ap) return NULL; e = nasm_vaxprintf(offsetin(*e, str), fmt, ap); - e->size = nasm_aprintf_size(); + e->size = nasm_last_string_size(); if (list->uniq) { void **dp = hash_findb(&list->hash, e->str, e->size, &hi);