summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2016-09-24 02:35:13 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2016-09-24 02:35:29 -0700
commitb3e1b382456b0f7d108c57d6f902bbddfdd97b2a (patch)
treeaa3bcb76dfb30dace2811de0612a569daf250d8d
parent4f05e930ca9ca4fa87aa2bc83187590432d792bd (diff)
downloademacs-b3e1b382456b0f7d108c57d6f902bbddfdd97b2a.tar.gz
Improve integer overflow handling a bit
* 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.
-rw-r--r--src/charset.c2
-rw-r--r--src/doprnt.c25
-rw-r--r--src/editfns.c15
-rw-r--r--src/emacs-module.c13
-rw-r--r--src/font.c7
-rw-r--r--src/keyboard.c8
-rw-r--r--src/lread.c10
-rw-r--r--src/xdisp.c64
8 files changed, 58 insertions, 86 deletions
diff --git a/src/charset.c b/src/charset.c
index 0c831f13591..cdbfe119515 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -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'
diff --git a/src/doprnt.c b/src/doprnt.c
index 9d8b783565f..de2b89e1225 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -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)
diff --git a/src/editfns.c b/src/editfns.c
index 835e432ae3d..c5b177e41f2 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -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;
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 724d24a7768..0e755ef956b 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -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>
/* 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));
}
diff --git a/src/font.c b/src/font.c
index 144ba07c42a..f2800633b62 100644
--- a/src/font.c
+++ b/src/font.c
@@ -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;
}
diff --git a/src/keyboard.c b/src/keyboard.c
index b8bc3610eb0..ca40c6e7ad0 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -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,
diff --git a/src/lread.c b/src/lread.c
index dc7c00bbfae..d3413d16cea 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -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);
diff --git a/src/xdisp.c b/src/xdisp.c
index 4bf1470e46c..13af87f953c 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -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;
}
}