]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve integer overflow handling a bit
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 24 Sep 2016 09:35:13 +0000 (02:35 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 24 Sep 2016 09:35:29 +0000 (02:35 -0700)
* src/charset.c (read_hex): Use INT_LEFT_SHIFT_OVERFLOW for clarity.
The machine code is the same on my platform.
* src/doprnt.c (doprnt):
* src/emacs-module.c (module_funcall):
* src/font.c (font_intern_prop):
* src/keyboard.c (Frecursion_depth):
* src/lread.c (read1):
Use WRAPV macros instead of checking overflow by hand.
* src/editfns.c (hi_time, time_arith, decode_time_components):
* src/emacs-module.c (Fmodule_load):
Simplify by using FIXNUM_OVERFLOW_P.
* src/emacs-module.c: Include intprops.h.
* src/xdisp.c (percent99): New function.
(decode_mode_spec): Use it to simplify overflow avoidance and
formatting of %p and %P.

src/charset.c
src/doprnt.c
src/editfns.c
src/emacs-module.c
src/font.c
src/keyboard.c
src/lread.c
src/xdisp.c

index 0c831f13591225fcfa1042c28ba18e838cf1ee0a..cdbfe119515424a22b2c4d0c698a6b0bc5151c94 100644 (file)
@@ -435,7 +435,7 @@ read_hex (FILE *fp, bool *eof, bool *overflow)
   n = 0;
   while (c_isxdigit (c = getc (fp)))
     {
-      if (UINT_MAX >> 4 < n)
+      if (INT_LEFT_SHIFT_OVERFLOW (n, 4))
        *overflow = 1;
       n = ((n << 4)
           | (c - ('0' <= c && c <= '9' ? '0'
index 9d8b783565fde52be8a8e7d72279742cf024f5b1..de2b89e1225a3c7629db235f611b64f12f0207f8 100644 (file)
@@ -133,8 +133,11 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
   const char *fmt = format;    /* Pointer into format string.  */
   char *bufptr = buffer;       /* Pointer into output buffer.  */
 
+  /* Enough to handle floating point formats with large numbers.  */
+  enum { SIZE_BOUND_EXTRA = DBL_MAX_10_EXP + 50 };
+
   /* Use this for sprintf unless we need something really big.  */
-  char tembuf[DBL_MAX_10_EXP + 100];
+  char tembuf[SIZE_BOUND_EXTRA + 50];
 
   /* Size of sprintf_buffer.  */
   ptrdiff_t size_allocated = sizeof (tembuf);
@@ -196,21 +199,19 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
                     This might be a field width or a precision; e.g.
                     %1.1000f and %1000.1f both might need 1000+ bytes.
                     Parse the width or precision, checking for overflow.  */
-                 ptrdiff_t n = *fmt - '0';
+                 int n = *fmt - '0';
+                 bool overflow = false;
                  while (fmt + 1 < format_end
                         && '0' <= fmt[1] && fmt[1] <= '9')
                    {
-                     /* Avoid ptrdiff_t, size_t, and int overflow, as
-                        many sprintfs mishandle widths greater than INT_MAX.
-                        This test is simple but slightly conservative: e.g.,
-                        (INT_MAX - INT_MAX % 10) is reported as an overflow
-                        even when it's not.  */
-                     if (n >= min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX)) / 10)
-                       error ("Format width or precision too large");
-                     n = n * 10 + fmt[1] - '0';
+                     overflow |= INT_MULTIPLY_WRAPV (n, 10, &n);
+                     overflow |= INT_ADD_WRAPV (n, fmt[1] - '0', &n);
                      *string++ = *++fmt;
                    }
 
+                 if (overflow
+                     || min (PTRDIFF_MAX, SIZE_MAX) - SIZE_BOUND_EXTRA < n)
+                   error ("Format width or precision too large");
                  if (size_bound < n)
                    size_bound = n;
                }
@@ -244,9 +245,7 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
 
          /* Make the size bound large enough to handle floating point formats
             with large numbers.  */
-         if (size_bound > min (PTRDIFF_MAX, SIZE_MAX) - DBL_MAX_10_EXP - 50)
-           error ("Format width or precision too large");
-         size_bound += DBL_MAX_10_EXP + 50;
+         size_bound += SIZE_BOUND_EXTRA;
 
          /* Make sure we have that much.  */
          if (size_bound > size_allocated)
index 835e432ae3d2fcfe02c83abc51e62487612e8712..c5b177e41f26720d791fd873caa8cfbab972bb6b 100644 (file)
@@ -1523,17 +1523,8 @@ static EMACS_INT
 hi_time (time_t t)
 {
   time_t hi = t >> LO_TIME_BITS;
-
-  /* Check for overflow, helping the compiler for common cases where
-     no runtime check is needed, and taking care not to convert
-     negative numbers to unsigned before comparing them.  */
-  if (! ((! TYPE_SIGNED (time_t)
-         || MOST_NEGATIVE_FIXNUM <= TIME_T_MIN >> LO_TIME_BITS
-         || MOST_NEGATIVE_FIXNUM <= hi)
-        && (TIME_T_MAX >> LO_TIME_BITS <= MOST_POSITIVE_FIXNUM
-            || hi <= MOST_POSITIVE_FIXNUM)))
+  if (FIXNUM_OVERFLOW_P (hi))
     time_overflow ();
-
   return hi;
 }
 
@@ -1595,7 +1586,7 @@ time_arith (Lisp_Object a, Lisp_Object b,
   struct lisp_time ta = lisp_time_struct (a, &alen);
   struct lisp_time tb = lisp_time_struct (b, &blen);
   struct lisp_time t = op (ta, tb);
-  if (! (MOST_NEGATIVE_FIXNUM <= t.hi && t.hi <= MOST_POSITIVE_FIXNUM))
+  if (FIXNUM_OVERFLOW_P (t.hi))
     time_overflow ();
   Lisp_Object val = Qnil;
 
@@ -1853,7 +1844,7 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec,
 
   if (result)
     {
-      if (! (MOST_NEGATIVE_FIXNUM <= hi && hi <= MOST_POSITIVE_FIXNUM))
+      if (FIXNUM_OVERFLOW_P (hi))
        return -1;
       result->hi = hi;
       result->lo = lo;
index 724d24a77688aa0249006e92e2f66d5ae2ab9b42..0e755ef956be64125764dcabbc87abbbd83cdfa0 100644 (file)
@@ -30,7 +30,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "dynlib.h"
 #include "coding.h"
-#include "verify.h"
+
+#include <intprops.h>
+#include <verify.h>
 
 \f
 /* Feature tests.  */
@@ -424,13 +426,14 @@ module_funcall (emacs_env *env, emacs_value fun, ptrdiff_t nargs,
      first arg, because that's what Ffuncall takes.  */
   Lisp_Object *newargs;
   USE_SAFE_ALLOCA;
-  if (nargs == PTRDIFF_MAX)
+  ptrdiff_t nargs1;
+  if (INT_ADD_WRAPV (nargs, 1, &nargs1))
     xsignal0 (Qoverflow_error);
-  SAFE_ALLOCA_LISP (newargs, nargs + 1);
+  SAFE_ALLOCA_LISP (newargs, nargs1);
   newargs[0] = value_to_lisp (fun);
   for (ptrdiff_t i = 0; i < nargs; i++)
     newargs[1 + i] = value_to_lisp (args[i]);
-  emacs_value result = lisp_to_value (Ffuncall (nargs + 1, newargs));
+  emacs_value result = lisp_to_value (Ffuncall (nargs1, newargs));
   SAFE_FREE ();
   return result;
 }
@@ -665,7 +668,7 @@ DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0,
 
   if (r != 0)
     {
-      if (! (MOST_NEGATIVE_FIXNUM <= r && r <= MOST_POSITIVE_FIXNUM))
+      if (FIXNUM_OVERFLOW_P (r))
         xsignal0 (Qoverflow_error);
       xsignal2 (Qmodule_load_failed, file, make_number (r));
     }
index 144ba07c42a09385f2f7e12562be46e39a953256..f2800633b629bbf3f3c230fa15b1f2bc94074cb6 100644 (file)
@@ -264,14 +264,13 @@ font_intern_prop (const char *str, ptrdiff_t len, bool force_symbol)
          break;
       if (i == len)
        {
-         EMACS_INT n;
-
          i = 0;
-         for (n = 0; (n += str[i++] - '0') <= MOST_POSITIVE_FIXNUM; n *= 10)
+         for (EMACS_INT n = 0;
+              (n += str[i++] - '0') <= MOST_POSITIVE_FIXNUM; )
            {
              if (i == len)
                return make_number (n);
-             if (MOST_POSITIVE_FIXNUM / 10 < n)
+             if (INT_MULTIPLY_WRAPV (n, 10, &n))
                break;
            }
 
index b8bc3610eb06d611e1b66a675f022a3f7e1b3789..ca40c6e7ad0086fa7acc7facc02f954a22246309 100644 (file)
@@ -10058,11 +10058,9 @@ DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
        doc: /* Return the current depth in recursive edits.  */)
   (void)
 {
-  Lisp_Object temp;
-  /* Wrap around reliably on integer overflow.  */
-  EMACS_INT sum = (command_loop_level & INTMASK) + (minibuf_level & INTMASK);
-  XSETINT (temp, sum);
-  return temp;
+  EMACS_INT sum;
+  INT_ADD_WRAPV (command_loop_level, minibuf_level, &sum);
+  return make_number (sum);
 }
 
 DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1,
index dc7c00bbfae68f27b3f728fdcd8168f9f8550f5c..d3413d16ceac7128068f334c57f20ff63deb003a 100644 (file)
@@ -2894,19 +2894,17 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
        {
          EMACS_INT n = 0;
          Lisp_Object tem;
+         bool overflow = false;
 
          /* Read a non-negative integer.  */
          while (c >= '0' && c <= '9')
            {
-             if (MOST_POSITIVE_FIXNUM / 10 < n
-                 || MOST_POSITIVE_FIXNUM < n * 10 + c - '0')
-               n = MOST_POSITIVE_FIXNUM + 1;
-             else
-               n = n * 10 + c - '0';
+             overflow |= INT_MULTIPLY_WRAPV (n, 10, &n);
+             overflow |= INT_ADD_WRAPV (n, c - '0', &n);
              c = READCHAR;
            }
 
-         if (n <= MOST_POSITIVE_FIXNUM)
+         if (!overflow && n <= MOST_POSITIVE_FIXNUM)
            {
              if (c == 'r' || c == 'R')
                return read_integer (readcharfun, n);
index 4bf1470e46c3a22340840c15688e034ea5676ea8..13af87f953c6cad2fbb83b99f95fc4c733726825 100644 (file)
@@ -23448,6 +23448,16 @@ decode_mode_spec_coding (Lisp_Object coding_system, char *buf, bool eol_flag)
   return buf;
 }
 
+/* Return the approximate percentage N is of D (rounding upward), or 99,
+   whichever is less.  Assume 0 < D and 0 <= N <= D * INT_MAX / 100.  */
+
+static int
+percent99 (ptrdiff_t n, ptrdiff_t d)
+{
+  int percent = (d - 1 + 100.0 * n) / d;
+  return min (percent, 99);
+}
+
 /* Return a string for the output of a mode line %-spec for window W,
    generated by character C.  FIELD_WIDTH > 0 means pad the string
    returned with spaces to that value.  Return a Lisp string in
@@ -23735,29 +23745,17 @@ decode_mode_spec (struct window *w, register int c, int field_width,
     case 'p':
       {
        ptrdiff_t pos = marker_position (w->start);
-       ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b);
+       ptrdiff_t begv = BUF_BEGV (b);
+       ptrdiff_t zv = BUF_ZV (b);
 
-       if (w->window_end_pos <= BUF_Z (b) - BUF_ZV (b))
-         {
-           if (pos <= BUF_BEGV (b))
-             return "All";
-           else
-             return "Bottom";
-         }
-       else if (pos <= BUF_BEGV (b))
+       if (w->window_end_pos <= BUF_Z (b) - zv)
+         return pos <= begv ? "All" : "Bottom";
+       else if (pos <= begv)
          return "Top";
        else
          {
-           if (total > 1000000)
-             /* Do it differently for a large value, to avoid overflow.  */
-             total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
-           else
-             total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total;
-           /* We can't normally display a 3-digit number,
-              so get us a 2-digit number that is close.  */
-           if (total == 100)
-             total = 99;
-           sprintf (decode_mode_spec_buf, "%2"pD"d%%", total);
+           sprintf (decode_mode_spec_buf, "%2d%%",
+                    percent99 (pos - begv, zv - begv));
            return decode_mode_spec_buf;
          }
       }
@@ -23767,30 +23765,16 @@ decode_mode_spec (struct window *w, register int c, int field_width,
       {
        ptrdiff_t toppos = marker_position (w->start);
        ptrdiff_t botpos = BUF_Z (b) - w->window_end_pos;
-       ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b);
+       ptrdiff_t begv = BUF_BEGV (b);
+       ptrdiff_t zv = BUF_ZV (b);
 
-       if (botpos >= BUF_ZV (b))
-         {
-           if (toppos <= BUF_BEGV (b))
-             return "All";
-           else
-             return "Bottom";
-         }
+       if (zv <= botpos)
+         return toppos <= begv ? "All" : "Bottom";
        else
          {
-           if (total > 1000000)
-             /* Do it differently for a large value, to avoid overflow.  */
-             total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100);
-           else
-             total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total;
-           /* We can't normally display a 3-digit number,
-              so get us a 2-digit number that is close.  */
-           if (total == 100)
-             total = 99;
-           if (toppos <= BUF_BEGV (b))
-             sprintf (decode_mode_spec_buf, "Top%2"pD"d%%", total);
-           else
-             sprintf (decode_mode_spec_buf, "%2"pD"d%%", total);
+           sprintf (decode_mode_spec_buf,
+                    &"Top%2d%%"[begv < toppos ? sizeof "Top" - 1 : 0],
+                    percent99 (botpos - begv, zv - begv));
            return decode_mode_spec_buf;
          }
       }