summaryrefslogtreecommitdiff
path: root/src/doprnt.c
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 /src/doprnt.c
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.
Diffstat (limited to 'src/doprnt.c')
-rw-r--r--src/doprnt.c25
1 files changed, 12 insertions, 13 deletions
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)