diff options
author | Bruno Haible <bruno@clisp.org> | 2021-05-10 13:26:33 -0500 |
---|---|---|
committer | Eric Blake <eblake@redhat.com> | 2021-05-10 13:29:23 -0500 |
commit | 61f8b953332e7730b72690a5eda706d4f134a229 (patch) | |
tree | 9824a8517ab2ca077b0d945bc6cd7d72bae998bc | |
parent | 29deab03dbfeca73c5e9fa1975b1533ce1c29ec2 (diff) | |
download | m4-61f8b953332e7730b72690a5eda706d4f134a229.tar.gz |
eval: avoid undefined behaviour when parsing -2147483648
* src/eval.c (eval_lex): Use an unsigned variable for accumulating the
value.
https://lists.gnu.org/archive/html/bug-m4/2021-05/msg00001.html
-rw-r--r-- | src/eval.c | 16 |
1 files changed, 10 insertions, 6 deletions
@@ -115,7 +115,11 @@ eval_lex (int32_t *val) if (c_isdigit (*eval_text)) { - int base, digit; + unsigned int base, digit; + /* The documentation says that "overflow silently results in wraparound". + Therefore use an unsigned integer type to avoid undefined behaviour + when parsing '-2147483648'. */ + uint32_t value; if (*eval_text == '0') { @@ -152,8 +156,7 @@ eval_lex (int32_t *val) else base = 10; - /* FIXME - this calculation can overflow. Consider xstrtol. */ - *val = 0; + value = 0; for (; *eval_text; eval_text++) { if (c_isdigit (*eval_text)) @@ -168,8 +171,8 @@ eval_lex (int32_t *val) if (base == 1) { if (digit == 1) - (*val)++; - else if (digit == 0 && !*val) + value++; + else if (digit == 0 && value == 0) continue; else break; @@ -177,8 +180,9 @@ eval_lex (int32_t *val) else if (digit >= base) break; else - *val = *val * base + digit; + value = value * base + digit; } + *val = value; return NUMBER; } |