]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
(toarith): Rewrite to detect/diagnose integer overflow,
authorJim Meyering <jim@meyering.net>
Fri, 14 Jan 2005 14:15:25 +0000 (14:15 +0000)
committerJim Meyering <jim@meyering.net>
Fri, 14 Jan 2005 14:15:25 +0000 (14:15 +0000)
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

index 2ba533bc8f1bac94200c4f139ada2e3665f6c996..5cc068a511a5077180295bf1ddbac6b02fca7c01 100644 (file)
@@ -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 ();
     }