diff options
| author | Paul Eggert | 2016-09-24 02:35:13 -0700 |
|---|---|---|
| committer | Paul Eggert | 2016-09-24 02:35:29 -0700 |
| commit | b3e1b382456b0f7d108c57d6f902bbddfdd97b2a (patch) | |
| tree | aa3bcb76dfb30dace2811de0612a569daf250d8d /src | |
| parent | 4f05e930ca9ca4fa87aa2bc83187590432d792bd (diff) | |
| download | emacs-b3e1b382456b0f7d108c57d6f902bbddfdd97b2a.tar.gz emacs-b3e1b382456b0f7d108c57d6f902bbddfdd97b2a.zip | |
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')
| -rw-r--r-- | src/charset.c | 2 | ||||
| -rw-r--r-- | src/doprnt.c | 25 | ||||
| -rw-r--r-- | src/editfns.c | 15 | ||||
| -rw-r--r-- | src/emacs-module.c | 13 | ||||
| -rw-r--r-- | src/font.c | 7 | ||||
| -rw-r--r-- | src/keyboard.c | 8 | ||||
| -rw-r--r-- | src/lread.c | 10 | ||||
| -rw-r--r-- | src/xdisp.c | 64 |
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) | |||
| 435 | n = 0; | 435 | n = 0; |
| 436 | while (c_isxdigit (c = getc (fp))) | 436 | while (c_isxdigit (c = getc (fp))) |
| 437 | { | 437 | { |
| 438 | if (UINT_MAX >> 4 < n) | 438 | if (INT_LEFT_SHIFT_OVERFLOW (n, 4)) |
| 439 | *overflow = 1; | 439 | *overflow = 1; |
| 440 | n = ((n << 4) | 440 | n = ((n << 4) |
| 441 | | (c - ('0' <= c && c <= '9' ? '0' | 441 | | (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, | |||
| 133 | const char *fmt = format; /* Pointer into format string. */ | 133 | const char *fmt = format; /* Pointer into format string. */ |
| 134 | char *bufptr = buffer; /* Pointer into output buffer. */ | 134 | char *bufptr = buffer; /* Pointer into output buffer. */ |
| 135 | 135 | ||
| 136 | /* Enough to handle floating point formats with large numbers. */ | ||
| 137 | enum { SIZE_BOUND_EXTRA = DBL_MAX_10_EXP + 50 }; | ||
| 138 | |||
| 136 | /* Use this for sprintf unless we need something really big. */ | 139 | /* Use this for sprintf unless we need something really big. */ |
| 137 | char tembuf[DBL_MAX_10_EXP + 100]; | 140 | char tembuf[SIZE_BOUND_EXTRA + 50]; |
| 138 | 141 | ||
| 139 | /* Size of sprintf_buffer. */ | 142 | /* Size of sprintf_buffer. */ |
| 140 | ptrdiff_t size_allocated = sizeof (tembuf); | 143 | ptrdiff_t size_allocated = sizeof (tembuf); |
| @@ -196,21 +199,19 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, | |||
| 196 | This might be a field width or a precision; e.g. | 199 | This might be a field width or a precision; e.g. |
| 197 | %1.1000f and %1000.1f both might need 1000+ bytes. | 200 | %1.1000f and %1000.1f both might need 1000+ bytes. |
| 198 | Parse the width or precision, checking for overflow. */ | 201 | Parse the width or precision, checking for overflow. */ |
| 199 | ptrdiff_t n = *fmt - '0'; | 202 | int n = *fmt - '0'; |
| 203 | bool overflow = false; | ||
| 200 | while (fmt + 1 < format_end | 204 | while (fmt + 1 < format_end |
| 201 | && '0' <= fmt[1] && fmt[1] <= '9') | 205 | && '0' <= fmt[1] && fmt[1] <= '9') |
| 202 | { | 206 | { |
| 203 | /* Avoid ptrdiff_t, size_t, and int overflow, as | 207 | overflow |= INT_MULTIPLY_WRAPV (n, 10, &n); |
| 204 | many sprintfs mishandle widths greater than INT_MAX. | 208 | overflow |= INT_ADD_WRAPV (n, fmt[1] - '0', &n); |
| 205 | This test is simple but slightly conservative: e.g., | ||
| 206 | (INT_MAX - INT_MAX % 10) is reported as an overflow | ||
| 207 | even when it's not. */ | ||
| 208 | if (n >= min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX)) / 10) | ||
| 209 | error ("Format width or precision too large"); | ||
| 210 | n = n * 10 + fmt[1] - '0'; | ||
| 211 | *string++ = *++fmt; | 209 | *string++ = *++fmt; |
| 212 | } | 210 | } |
| 213 | 211 | ||
| 212 | if (overflow | ||
| 213 | || min (PTRDIFF_MAX, SIZE_MAX) - SIZE_BOUND_EXTRA < n) | ||
| 214 | error ("Format width or precision too large"); | ||
| 214 | if (size_bound < n) | 215 | if (size_bound < n) |
| 215 | size_bound = n; | 216 | size_bound = n; |
| 216 | } | 217 | } |
| @@ -244,9 +245,7 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, | |||
| 244 | 245 | ||
| 245 | /* Make the size bound large enough to handle floating point formats | 246 | /* Make the size bound large enough to handle floating point formats |
| 246 | with large numbers. */ | 247 | with large numbers. */ |
| 247 | if (size_bound > min (PTRDIFF_MAX, SIZE_MAX) - DBL_MAX_10_EXP - 50) | 248 | size_bound += SIZE_BOUND_EXTRA; |
| 248 | error ("Format width or precision too large"); | ||
| 249 | size_bound += DBL_MAX_10_EXP + 50; | ||
| 250 | 249 | ||
| 251 | /* Make sure we have that much. */ | 250 | /* Make sure we have that much. */ |
| 252 | if (size_bound > size_allocated) | 251 | 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 | |||
| 1523 | hi_time (time_t t) | 1523 | hi_time (time_t t) |
| 1524 | { | 1524 | { |
| 1525 | time_t hi = t >> LO_TIME_BITS; | 1525 | time_t hi = t >> LO_TIME_BITS; |
| 1526 | 1526 | if (FIXNUM_OVERFLOW_P (hi)) | |
| 1527 | /* Check for overflow, helping the compiler for common cases where | ||
| 1528 | no runtime check is needed, and taking care not to convert | ||
| 1529 | negative numbers to unsigned before comparing them. */ | ||
| 1530 | if (! ((! TYPE_SIGNED (time_t) | ||
| 1531 | || MOST_NEGATIVE_FIXNUM <= TIME_T_MIN >> LO_TIME_BITS | ||
| 1532 | || MOST_NEGATIVE_FIXNUM <= hi) | ||
| 1533 | && (TIME_T_MAX >> LO_TIME_BITS <= MOST_POSITIVE_FIXNUM | ||
| 1534 | || hi <= MOST_POSITIVE_FIXNUM))) | ||
| 1535 | time_overflow (); | 1527 | time_overflow (); |
| 1536 | |||
| 1537 | return hi; | 1528 | return hi; |
| 1538 | } | 1529 | } |
| 1539 | 1530 | ||
| @@ -1595,7 +1586,7 @@ time_arith (Lisp_Object a, Lisp_Object b, | |||
| 1595 | struct lisp_time ta = lisp_time_struct (a, &alen); | 1586 | struct lisp_time ta = lisp_time_struct (a, &alen); |
| 1596 | struct lisp_time tb = lisp_time_struct (b, &blen); | 1587 | struct lisp_time tb = lisp_time_struct (b, &blen); |
| 1597 | struct lisp_time t = op (ta, tb); | 1588 | struct lisp_time t = op (ta, tb); |
| 1598 | if (! (MOST_NEGATIVE_FIXNUM <= t.hi && t.hi <= MOST_POSITIVE_FIXNUM)) | 1589 | if (FIXNUM_OVERFLOW_P (t.hi)) |
| 1599 | time_overflow (); | 1590 | time_overflow (); |
| 1600 | Lisp_Object val = Qnil; | 1591 | Lisp_Object val = Qnil; |
| 1601 | 1592 | ||
| @@ -1853,7 +1844,7 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, | |||
| 1853 | 1844 | ||
| 1854 | if (result) | 1845 | if (result) |
| 1855 | { | 1846 | { |
| 1856 | if (! (MOST_NEGATIVE_FIXNUM <= hi && hi <= MOST_POSITIVE_FIXNUM)) | 1847 | if (FIXNUM_OVERFLOW_P (hi)) |
| 1857 | return -1; | 1848 | return -1; |
| 1858 | result->hi = hi; | 1849 | result->hi = hi; |
| 1859 | result->lo = lo; | 1850 | 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/>. */ | |||
| 30 | #include "lisp.h" | 30 | #include "lisp.h" |
| 31 | #include "dynlib.h" | 31 | #include "dynlib.h" |
| 32 | #include "coding.h" | 32 | #include "coding.h" |
| 33 | #include "verify.h" | 33 | |
| 34 | #include <intprops.h> | ||
| 35 | #include <verify.h> | ||
| 34 | 36 | ||
| 35 | 37 | ||
| 36 | /* Feature tests. */ | 38 | /* Feature tests. */ |
| @@ -424,13 +426,14 @@ module_funcall (emacs_env *env, emacs_value fun, ptrdiff_t nargs, | |||
| 424 | first arg, because that's what Ffuncall takes. */ | 426 | first arg, because that's what Ffuncall takes. */ |
| 425 | Lisp_Object *newargs; | 427 | Lisp_Object *newargs; |
| 426 | USE_SAFE_ALLOCA; | 428 | USE_SAFE_ALLOCA; |
| 427 | if (nargs == PTRDIFF_MAX) | 429 | ptrdiff_t nargs1; |
| 430 | if (INT_ADD_WRAPV (nargs, 1, &nargs1)) | ||
| 428 | xsignal0 (Qoverflow_error); | 431 | xsignal0 (Qoverflow_error); |
| 429 | SAFE_ALLOCA_LISP (newargs, nargs + 1); | 432 | SAFE_ALLOCA_LISP (newargs, nargs1); |
| 430 | newargs[0] = value_to_lisp (fun); | 433 | newargs[0] = value_to_lisp (fun); |
| 431 | for (ptrdiff_t i = 0; i < nargs; i++) | 434 | for (ptrdiff_t i = 0; i < nargs; i++) |
| 432 | newargs[1 + i] = value_to_lisp (args[i]); | 435 | newargs[1 + i] = value_to_lisp (args[i]); |
| 433 | emacs_value result = lisp_to_value (Ffuncall (nargs + 1, newargs)); | 436 | emacs_value result = lisp_to_value (Ffuncall (nargs1, newargs)); |
| 434 | SAFE_FREE (); | 437 | SAFE_FREE (); |
| 435 | return result; | 438 | return result; |
| 436 | } | 439 | } |
| @@ -665,7 +668,7 @@ DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0, | |||
| 665 | 668 | ||
| 666 | if (r != 0) | 669 | if (r != 0) |
| 667 | { | 670 | { |
| 668 | if (! (MOST_NEGATIVE_FIXNUM <= r && r <= MOST_POSITIVE_FIXNUM)) | 671 | if (FIXNUM_OVERFLOW_P (r)) |
| 669 | xsignal0 (Qoverflow_error); | 672 | xsignal0 (Qoverflow_error); |
| 670 | xsignal2 (Qmodule_load_failed, file, make_number (r)); | 673 | xsignal2 (Qmodule_load_failed, file, make_number (r)); |
| 671 | } | 674 | } |
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) | |||
| 264 | break; | 264 | break; |
| 265 | if (i == len) | 265 | if (i == len) |
| 266 | { | 266 | { |
| 267 | EMACS_INT n; | ||
| 268 | |||
| 269 | i = 0; | 267 | i = 0; |
| 270 | for (n = 0; (n += str[i++] - '0') <= MOST_POSITIVE_FIXNUM; n *= 10) | 268 | for (EMACS_INT n = 0; |
| 269 | (n += str[i++] - '0') <= MOST_POSITIVE_FIXNUM; ) | ||
| 271 | { | 270 | { |
| 272 | if (i == len) | 271 | if (i == len) |
| 273 | return make_number (n); | 272 | return make_number (n); |
| 274 | if (MOST_POSITIVE_FIXNUM / 10 < n) | 273 | if (INT_MULTIPLY_WRAPV (n, 10, &n)) |
| 275 | break; | 274 | break; |
| 276 | } | 275 | } |
| 277 | 276 | ||
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, | |||
| 10058 | doc: /* Return the current depth in recursive edits. */) | 10058 | doc: /* Return the current depth in recursive edits. */) |
| 10059 | (void) | 10059 | (void) |
| 10060 | { | 10060 | { |
| 10061 | Lisp_Object temp; | 10061 | EMACS_INT sum; |
| 10062 | /* Wrap around reliably on integer overflow. */ | 10062 | INT_ADD_WRAPV (command_loop_level, minibuf_level, &sum); |
| 10063 | EMACS_INT sum = (command_loop_level & INTMASK) + (minibuf_level & INTMASK); | 10063 | return make_number (sum); |
| 10064 | XSETINT (temp, sum); | ||
| 10065 | return temp; | ||
| 10066 | } | 10064 | } |
| 10067 | 10065 | ||
| 10068 | DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1, | 10066 | 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) | |||
| 2894 | { | 2894 | { |
| 2895 | EMACS_INT n = 0; | 2895 | EMACS_INT n = 0; |
| 2896 | Lisp_Object tem; | 2896 | Lisp_Object tem; |
| 2897 | bool overflow = false; | ||
| 2897 | 2898 | ||
| 2898 | /* Read a non-negative integer. */ | 2899 | /* Read a non-negative integer. */ |
| 2899 | while (c >= '0' && c <= '9') | 2900 | while (c >= '0' && c <= '9') |
| 2900 | { | 2901 | { |
| 2901 | if (MOST_POSITIVE_FIXNUM / 10 < n | 2902 | overflow |= INT_MULTIPLY_WRAPV (n, 10, &n); |
| 2902 | || MOST_POSITIVE_FIXNUM < n * 10 + c - '0') | 2903 | overflow |= INT_ADD_WRAPV (n, c - '0', &n); |
| 2903 | n = MOST_POSITIVE_FIXNUM + 1; | ||
| 2904 | else | ||
| 2905 | n = n * 10 + c - '0'; | ||
| 2906 | c = READCHAR; | 2904 | c = READCHAR; |
| 2907 | } | 2905 | } |
| 2908 | 2906 | ||
| 2909 | if (n <= MOST_POSITIVE_FIXNUM) | 2907 | if (!overflow && n <= MOST_POSITIVE_FIXNUM) |
| 2910 | { | 2908 | { |
| 2911 | if (c == 'r' || c == 'R') | 2909 | if (c == 'r' || c == 'R') |
| 2912 | return read_integer (readcharfun, n); | 2910 | 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) | |||
| 23448 | return buf; | 23448 | return buf; |
| 23449 | } | 23449 | } |
| 23450 | 23450 | ||
| 23451 | /* Return the approximate percentage N is of D (rounding upward), or 99, | ||
| 23452 | whichever is less. Assume 0 < D and 0 <= N <= D * INT_MAX / 100. */ | ||
| 23453 | |||
| 23454 | static int | ||
| 23455 | percent99 (ptrdiff_t n, ptrdiff_t d) | ||
| 23456 | { | ||
| 23457 | int percent = (d - 1 + 100.0 * n) / d; | ||
| 23458 | return min (percent, 99); | ||
| 23459 | } | ||
| 23460 | |||
| 23451 | /* Return a string for the output of a mode line %-spec for window W, | 23461 | /* Return a string for the output of a mode line %-spec for window W, |
| 23452 | generated by character C. FIELD_WIDTH > 0 means pad the string | 23462 | generated by character C. FIELD_WIDTH > 0 means pad the string |
| 23453 | returned with spaces to that value. Return a Lisp string in | 23463 | 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, | |||
| 23735 | case 'p': | 23745 | case 'p': |
| 23736 | { | 23746 | { |
| 23737 | ptrdiff_t pos = marker_position (w->start); | 23747 | ptrdiff_t pos = marker_position (w->start); |
| 23738 | ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b); | 23748 | ptrdiff_t begv = BUF_BEGV (b); |
| 23749 | ptrdiff_t zv = BUF_ZV (b); | ||
| 23739 | 23750 | ||
| 23740 | if (w->window_end_pos <= BUF_Z (b) - BUF_ZV (b)) | 23751 | if (w->window_end_pos <= BUF_Z (b) - zv) |
| 23741 | { | 23752 | return pos <= begv ? "All" : "Bottom"; |
| 23742 | if (pos <= BUF_BEGV (b)) | 23753 | else if (pos <= begv) |
| 23743 | return "All"; | ||
| 23744 | else | ||
| 23745 | return "Bottom"; | ||
| 23746 | } | ||
| 23747 | else if (pos <= BUF_BEGV (b)) | ||
| 23748 | return "Top"; | 23754 | return "Top"; |
| 23749 | else | 23755 | else |
| 23750 | { | 23756 | { |
| 23751 | if (total > 1000000) | 23757 | sprintf (decode_mode_spec_buf, "%2d%%", |
| 23752 | /* Do it differently for a large value, to avoid overflow. */ | 23758 | percent99 (pos - begv, zv - begv)); |
| 23753 | total = ((pos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100); | ||
| 23754 | else | ||
| 23755 | total = ((pos - BUF_BEGV (b)) * 100 + total - 1) / total; | ||
| 23756 | /* We can't normally display a 3-digit number, | ||
| 23757 | so get us a 2-digit number that is close. */ | ||
| 23758 | if (total == 100) | ||
| 23759 | total = 99; | ||
| 23760 | sprintf (decode_mode_spec_buf, "%2"pD"d%%", total); | ||
| 23761 | return decode_mode_spec_buf; | 23759 | return decode_mode_spec_buf; |
| 23762 | } | 23760 | } |
| 23763 | } | 23761 | } |
| @@ -23767,30 +23765,16 @@ decode_mode_spec (struct window *w, register int c, int field_width, | |||
| 23767 | { | 23765 | { |
| 23768 | ptrdiff_t toppos = marker_position (w->start); | 23766 | ptrdiff_t toppos = marker_position (w->start); |
| 23769 | ptrdiff_t botpos = BUF_Z (b) - w->window_end_pos; | 23767 | ptrdiff_t botpos = BUF_Z (b) - w->window_end_pos; |
| 23770 | ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b); | 23768 | ptrdiff_t begv = BUF_BEGV (b); |
| 23769 | ptrdiff_t zv = BUF_ZV (b); | ||
| 23771 | 23770 | ||
| 23772 | if (botpos >= BUF_ZV (b)) | 23771 | if (zv <= botpos) |
| 23773 | { | 23772 | return toppos <= begv ? "All" : "Bottom"; |
| 23774 | if (toppos <= BUF_BEGV (b)) | ||
| 23775 | return "All"; | ||
| 23776 | else | ||
| 23777 | return "Bottom"; | ||
| 23778 | } | ||
| 23779 | else | 23773 | else |
| 23780 | { | 23774 | { |
| 23781 | if (total > 1000000) | 23775 | sprintf (decode_mode_spec_buf, |
| 23782 | /* Do it differently for a large value, to avoid overflow. */ | 23776 | &"Top%2d%%"[begv < toppos ? sizeof "Top" - 1 : 0], |
| 23783 | total = ((botpos - BUF_BEGV (b)) + (total / 100) - 1) / (total / 100); | 23777 | percent99 (botpos - begv, zv - begv)); |
| 23784 | else | ||
| 23785 | total = ((botpos - BUF_BEGV (b)) * 100 + total - 1) / total; | ||
| 23786 | /* We can't normally display a 3-digit number, | ||
| 23787 | so get us a 2-digit number that is close. */ | ||
| 23788 | if (total == 100) | ||
| 23789 | total = 99; | ||
| 23790 | if (toppos <= BUF_BEGV (b)) | ||
| 23791 | sprintf (decode_mode_spec_buf, "Top%2"pD"d%%", total); | ||
| 23792 | else | ||
| 23793 | sprintf (decode_mode_spec_buf, "%2"pD"d%%", total); | ||
| 23794 | return decode_mode_spec_buf; | 23778 | return decode_mode_spec_buf; |
| 23795 | } | 23779 | } |
| 23796 | } | 23780 | } |