diff options
author | Jim Meyering <jim@meyering.net> | 2005-01-14 14:15:25 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2005-01-14 14:15:25 +0000 |
commit | 7eff5901c419afb8945bd96a5ed12d196802bc79 (patch) | |
tree | 4b14cd3abd5b554d54531af4c4b0937ac2815bfa /src/expr.c | |
parent | 9eea26656326f27517c042a88d817a4a32ab938b (diff) | |
download | coreutils-7eff5901c419afb8945bd96a5ed12d196802bc79.tar.xz |
(toarith): Rewrite to detect/diagnose integer overflow,
rather than suffering silently.
Before, expr would silently overflow and wrap around:
$ expr 9223372036854775808 = 0 # $(echo 2^63|bc)
1
Now it detects the problem and exits nonzero:
$ ./expr $(echo 2^63|bc) = 0
./expr: 9223372036854775808: integer is too large
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/src/expr.c b/src/expr.c index 2ba533bc8..5cc068a51 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1,5 +1,5 @@ /* expr -- evaluate expressions. - Copyright (C) 86, 1991-1997, 1999-2004 Free Software Foundation, Inc. + Copyright (C) 86, 1991-1997, 1999-2005 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -322,34 +322,44 @@ tostring (VALUE *v) static bool toarith (VALUE *v) { - intmax_t i; - bool neg; - char *cp; - switch (v->type) { case integer: return true; case string: - i = 0; - cp = v->u.s; - neg = (*cp == '-'); - if (neg) - cp++; + { + intmax_t value = 0; + char *cp = v->u.s; + int sign = (*cp == '-' ? -1 : 1); - do - { - if (ISDIGIT (*cp)) - i = i * 10 + *cp - '0'; - else - return false; - } - while (*++cp); + if (sign < 0) + cp++; - free (v->u.s); - v->u.i = i * (neg ? -1 : 1); - v->type = integer; - return true; + do + { + if (ISDIGIT (*cp)) + { + intmax_t new_v = 10 * value + sign * (*cp - '0'); + if (0 < sign + ? (INTMAX_MAX / 10 < value || new_v < 0) + : (value < INTMAX_MIN / 10 || 0 < new_v)) + error (EXPR_FAILURE, 0, + (0 < sign + ? _("integer is too large: %s") + : _("integer is too small: %s")), + quotearg_colon (v->u.s)); + value = new_v; + } + else + return false; + } + while (*++cp); + + free (v->u.s); + v->u.i = value * sign; + v->type = integer; + return true; + } default: abort (); } |