summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2021-05-10 13:26:33 -0500
committerEric Blake <eblake@redhat.com>2021-05-10 13:29:23 -0500
commit61f8b953332e7730b72690a5eda706d4f134a229 (patch)
tree9824a8517ab2ca077b0d945bc6cd7d72bae998bc
parent29deab03dbfeca73c5e9fa1975b1533ce1c29ec2 (diff)
downloadm4-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.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/src/eval.c b/src/eval.c
index 31d0f3c7..4717c3cf 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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;
}