summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin (Intel) <hpa@zytor.com>2019-08-15 19:26:52 -0700
committerH. Peter Anvin (Intel) <hpa@zytor.com>2019-08-15 19:26:52 -0700
commit9fbd9fb8596af9fd4cdf6a962e53f9d5e18d7d87 (patch)
tree45e4e7a0fe64d4f64a04f44160523e0ad9120331
parent743c91855ec8995022f7aa562c44ae0aa474fc50 (diff)
downloadnasm-9fbd9fb8596af9fd4cdf6a962e53f9d5e18d7d87.tar.gz
preproc: fix mmacro nesting prevention
BR 3392602: mmacros should not nest unless so explicitly specified. Reported-by: C. Masloch <pushbx@38.de> Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
-rw-r--r--asm/nasm.c3
-rw-r--r--asm/preproc.c59
-rw-r--r--include/nasm.h1
3 files changed, 47 insertions, 16 deletions
diff --git a/asm/nasm.c b/asm/nasm.c
index c6ff9ec8..c84d6750 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -190,7 +190,8 @@ static const struct limit_info limit_info[LIMIT_MAX+1] = {
{ "passes", "total number of passes", LIMIT_MAX_VAL },
{ "stalled-passes", "number of passes without forward progress", 1000 },
{ "macro-levels", "levels of macro expansion", 10000 },
- { "macro-tokens", "tokens processed during macro expansion", 10000000 },
+ { "macro-tokens", "tokens processed during single-lime macro expansion", 10000000 },
+ { "mmacros", "multi-line macros before final return", 100000 },
{ "rep", "%rep count", 1000000 },
{ "eval", "expression evaluation descent", 1000000},
{ "lines", "total source lines processed", 2000000000 }
diff --git a/asm/preproc.c b/asm/preproc.c
index 24deb2d7..b40417ac 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -299,6 +299,18 @@ struct Include {
struct hash_table FileHash;
/*
+ * Counters to trap on insane macro recursion or processing.
+ * Note: for smacros these count *down*, for mmacros they count *up*.
+ */
+struct deadman {
+ int64_t total; /* Total number of macros/tokens */
+ int64_t levels; /* Descent depth across all macros */
+ bool triggered; /* Already triggered, no need for error msg */
+};
+
+static struct deadman smacro_deadman, mmacro_deadman;
+
+/*
* Conditional assembly: we maintain a separate stack of these for
* each level of file inclusion. (The only reason we keep the
* stacks separate is to ensure that a stray `%endif' in a file
@@ -3089,9 +3101,10 @@ issue_error:
if (defining)
nasm_fatal("`%s': already defining a macro", dname);
- defining = nasm_zalloc(sizeof(MMacro));
- defining->max_depth = nasm_limit[LIMIT_MACRO_LEVELS];
+ nasm_new(defining);
defining->casesense = casesense;
+ if (i == PP_RMACRO)
+ defining->max_depth = nasm_limit[LIMIT_MACRO_LEVELS];
if (!parse_mmacro_spec(tline, defining, dname)) {
nasm_free(defining);
goto done;
@@ -4289,11 +4302,6 @@ static Token *expand_mmac_params(Token * tline)
}
static Token *expand_smacro_noreset(Token * tline);
-static struct {
- int64_t tokens;
- int64_t levels;
- bool triggered;
-} smacro_deadman;
/*
* Expand *one* single-line macro instance. If the first token is not
@@ -4324,10 +4332,10 @@ static SMacro *expand_one_smacro(Token ***tpp)
mname = tline->text;
- smacro_deadman.tokens--;
+ smacro_deadman.total--;
smacro_deadman.levels--;
- if (unlikely(smacro_deadman.tokens < 0 || smacro_deadman.levels < 0)) {
+ if (unlikely(smacro_deadman.total < 0 || smacro_deadman.levels < 0)) {
if (unlikely(!smacro_deadman.triggered)) {
nasm_nonfatal("interminable macro recursion");
smacro_deadman.triggered = true;
@@ -4660,7 +4668,7 @@ done:
*/
static Token *expand_smacro(Token *tline)
{
- smacro_deadman.tokens = nasm_limit[LIMIT_MACRO_TOKENS];
+ smacro_deadman.total = nasm_limit[LIMIT_MACRO_TOKENS];
smacro_deadman.levels = nasm_limit[LIMIT_MACRO_LEVELS];
smacro_deadman.triggered = false;
return expand_smacro_noreset(tline);
@@ -5008,6 +5016,18 @@ static int expand_mmacro(Token * tline)
tline = t;
}
+ if (unlikely(mmacro_deadman.total >= nasm_limit[LIMIT_MMACROS] ||
+ mmacro_deadman.levels >= nasm_limit[LIMIT_MACRO_LEVELS])) {
+ if (!mmacro_deadman.triggered) {
+ nasm_nonfatal("interminable multiline macro recursion");
+ mmacro_deadman.triggered = true;
+ }
+ return 0;
+ }
+
+ mmacro_deadman.total++;
+ mmacro_deadman.levels++;
+
/*
* Fix up the parameters: this involves stripping leading and
* trailing whitespace, then stripping braces if they are
@@ -5059,10 +5079,9 @@ static int expand_mmacro(Token * tline)
* macro as in progress, and set up its invocation-specific
* variables.
*/
- ll = nasm_malloc(sizeof(Line));
+ nasm_new(ll);
ll->next = istk->expansion;
ll->finishes = m;
- ll->first = NULL;
istk->expansion = ll;
/*
@@ -5088,8 +5107,7 @@ static int expand_mmacro(Token * tline)
list_for_each(l, m->expansion) {
Token **tail;
- ll = nasm_malloc(sizeof(Line));
- ll->finishes = NULL;
+ nasm_new(ll);
ll->next = istk->expansion;
istk->expansion = ll;
tail = &ll->first;
@@ -5450,8 +5468,19 @@ static Token *pp_tokline(void)
/*
* This was a real macro call, not a %rep, and
* therefore the parameter information needs to
- * be freed.
+ * be freed and the iteration count/nesting
+ * depth adjusted.
*/
+
+ if (!--mmacro_deadman.levels) {
+ /*
+ * If all mmacro processing done,
+ * clear all counters and the deadman
+ * message trigger.
+ */
+ nasm_zero(mmacro_deadman); /* Clear all counters */
+ }
+
if (m->prev) {
pop_mmacro(m);
l->finishes->in_progress --;
diff --git a/include/nasm.h b/include/nasm.h
index 860d1fc0..cfeb13ce 100644
--- a/include/nasm.h
+++ b/include/nasm.h
@@ -755,6 +755,7 @@ enum nasm_limit {
LIMIT_STALLED,
LIMIT_MACRO_LEVELS,
LIMIT_MACRO_TOKENS,
+ LIMIT_MMACROS,
LIMIT_REP,
LIMIT_EVAL,
LIMIT_LINES