From 7eff5901c419afb8945bd96a5ed12d196802bc79 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Fri, 14 Jan 2005 14:15:25 +0000 Subject: (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 --- src/expr.c | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) (limited to 'src') 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 (); } -- cgit v1.2.3-70-g09d2