aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2018-03-29 10:16:29 -0700
committerPaul Eggert2018-03-29 11:03:07 -0700
commit6b3d01dad415230ad0bd0d01a05351d7a8b0e8c3 (patch)
treed49bf4520d6afc830aa9d016be3d57349b251c4f
parent3409fe0362c52127c52f854a7300f4dde4b8fffe (diff)
downloademacs-6b3d01dad415230ad0bd0d01a05351d7a8b0e8c3.tar.gz
emacs-6b3d01dad415230ad0bd0d01a05351d7a8b0e8c3.zip
Lisp reader now checks for integer overflow
* doc/lispref/numbers.texi (Integer Basics), etc/NEWS: Document this. * src/lisp.h (S2N_IGNORE_TRAILING, S2N_OVERFLOW_TO_FLOAT): New constants. * src/lread.c (string_to_number): Change trailing bool arg to integer argument with flags, to support S2N_OVERFLOW_TO_FLOAT. All uses changed. * test/src/editfns-tests.el (read-large-integer): New test.
-rw-r--r--doc/lispref/numbers.texi14
-rw-r--r--etc/NEWS7
-rw-r--r--src/data.c9
-rw-r--r--src/lisp.h3
-rw-r--r--src/lread.c35
-rw-r--r--src/process.c2
-rw-r--r--test/src/editfns-tests.el22
7 files changed, 62 insertions, 30 deletions
diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi
index c2cb6651d47..2fed2b642fd 100644
--- a/doc/lispref/numbers.texi
+++ b/doc/lispref/numbers.texi
@@ -55,16 +55,13 @@ chapter assume the minimum integer width of 30 bits.
55 55
56 The Lisp reader reads an integer as a nonempty sequence 56 The Lisp reader reads an integer as a nonempty sequence
57of decimal digits with optional initial sign and optional 57of decimal digits with optional initial sign and optional
58final period. A decimal integer that is out of the 58final period.
59Emacs range is treated as a floating-point number.
60 59
61@example 60@example
62 1 ; @r{The integer 1.} 61 1 ; @r{The integer 1.}
63 1. ; @r{The integer 1.} 62 1. ; @r{The integer 1.}
64+1 ; @r{Also the integer 1.} 63+1 ; @r{Also the integer 1.}
65-1 ; @r{The integer @minus{}1.} 64-1 ; @r{The integer @minus{}1.}
66 9000000000000000000
67 ; @r{The floating-point number 9e18.}
68 0 ; @r{The integer 0.} 65 0 ; @r{The integer 0.}
69-0 ; @r{The integer 0.} 66-0 ; @r{The integer 0.}
70@end example 67@end example
@@ -94,6 +91,15 @@ For example:
94#24r1k @result{} 44 91#24r1k @result{} 44
95@end example 92@end example
96 93
94 If an integer is outside the Emacs range, the Lisp reader ordinarily
95signals an overflow. However, if a too-large plain integer ends in a
96period, the Lisp reader treats it as a floating-point number instead.
97This lets an Emacs Lisp program specify a large integer that is
98quietly approximated by a floating-point number on machines with
99limited word width. For example, @samp{536870912.} is a
100floating-point number if Emacs integers are only 30 bits wide and is
101an integer otherwise.
102
97 To understand how various functions work on integers, especially the 103 To understand how various functions work on integers, especially the
98bitwise operators (@pxref{Bitwise Operations}), it is often helpful to 104bitwise operators (@pxref{Bitwise Operations}), it is often helpful to
99view the numbers in their binary form. 105view the numbers in their binary form.
diff --git a/etc/NEWS b/etc/NEWS
index 046d71b0f2f..9161f2bd323 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -352,6 +352,13 @@ as new-style, bind the new variable 'force-new-style-backquotes' to t.
352integer, Emacs now signals an error if the number is too large for the 352integer, Emacs now signals an error if the number is too large for the
353implementation to format (Bug#30408). 353implementation to format (Bug#30408).
354 354
355+++
356** The Lisp reader now signals an overflow for plain decimal integers
357that do not end in '.' and are outside Emacs range. Formerly the Lisp
358reader silently converted them to floating-point numbers, and signaled
359overflow only for integers with a radix that are outside machine range
360(Bug#30408).
361
355--- 362---
356** Some functions and variables obsolete since Emacs 22 have been removed: 363** Some functions and variables obsolete since Emacs 22 have been removed:
357archive-mouse-extract, assoc-ignore-case, assoc-ignore-representation, 364archive-mouse-extract, assoc-ignore-case, assoc-ignore-representation,
diff --git a/src/data.c b/src/data.c
index a7fab1ef58a..6f23a26757a 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2716,9 +2716,7 @@ present, base 10 is used. BASE must be between 2 and 16 (inclusive).
2716If the base used is not 10, STRING is always parsed as an integer. */) 2716If the base used is not 10, STRING is always parsed as an integer. */)
2717 (register Lisp_Object string, Lisp_Object base) 2717 (register Lisp_Object string, Lisp_Object base)
2718{ 2718{
2719 register char *p; 2719 int b;
2720 register int b;
2721 Lisp_Object val;
2722 2720
2723 CHECK_STRING (string); 2721 CHECK_STRING (string);
2724 2722
@@ -2732,11 +2730,12 @@ If the base used is not 10, STRING is always parsed as an integer. */)
2732 b = XINT (base); 2730 b = XINT (base);
2733 } 2731 }
2734 2732
2735 p = SSDATA (string); 2733 char *p = SSDATA (string);
2736 while (*p == ' ' || *p == '\t') 2734 while (*p == ' ' || *p == '\t')
2737 p++; 2735 p++;
2738 2736
2739 val = string_to_number (p, b, true); 2737 int flags = S2N_IGNORE_TRAILING | S2N_OVERFLOW_TO_FLOAT;
2738 Lisp_Object val = string_to_number (p, b, flags);
2740 return NILP (val) ? make_number (0) : val; 2739 return NILP (val) ? make_number (0) : val;
2741} 2740}
2742 2741
diff --git a/src/lisp.h b/src/lisp.h
index f0c0c5a14a5..b931d23bf38 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3899,7 +3899,8 @@ LOADHIST_ATTACH (Lisp_Object x)
3899} 3899}
3900extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, 3900extern int openp (Lisp_Object, Lisp_Object, Lisp_Object,
3901 Lisp_Object *, Lisp_Object, bool); 3901 Lisp_Object *, Lisp_Object, bool);
3902extern Lisp_Object string_to_number (char const *, int, bool); 3902enum { S2N_IGNORE_TRAILING = 1, S2N_OVERFLOW_TO_FLOAT = 2 };
3903extern Lisp_Object string_to_number (char const *, int, int);
3903extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), 3904extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
3904 Lisp_Object); 3905 Lisp_Object);
3905extern void dir_warning (const char *, Lisp_Object); 3906extern void dir_warning (const char *, Lisp_Object);
diff --git a/src/lread.c b/src/lread.c
index 381f9cf20c5..a774524ee43 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2339,7 +2339,7 @@ character_name_to_code (char const *name, ptrdiff_t name_len)
2339 monstrosities like "U+-0000". */ 2339 monstrosities like "U+-0000". */
2340 Lisp_Object code 2340 Lisp_Object code
2341 = (name[0] == 'U' && name[1] == '+' 2341 = (name[0] == 'U' && name[1] == '+'
2342 ? string_to_number (name + 1, 16, false) 2342 ? string_to_number (name + 1, 16, 0)
2343 : call2 (Qchar_from_name, make_unibyte_string (name, name_len), Qt)); 2343 : call2 (Qchar_from_name, make_unibyte_string (name, name_len), Qt));
2344 2344
2345 if (! RANGED_INTEGERP (0, code, MAX_UNICODE_CHAR) 2345 if (! RANGED_INTEGERP (0, code, MAX_UNICODE_CHAR)
@@ -2693,7 +2693,7 @@ read_integer (Lisp_Object readcharfun, EMACS_INT radix)
2693 invalid_syntax (buf); 2693 invalid_syntax (buf);
2694 } 2694 }
2695 2695
2696 return string_to_number (buf, radix, false); 2696 return string_to_number (buf, radix, 0);
2697} 2697}
2698 2698
2699 2699
@@ -3502,7 +3502,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3502 3502
3503 if (!quoted && !uninterned_symbol) 3503 if (!quoted && !uninterned_symbol)
3504 { 3504 {
3505 Lisp_Object result = string_to_number (read_buffer, 10, false); 3505 Lisp_Object result = string_to_number (read_buffer, 10, 0);
3506 if (! NILP (result)) 3506 if (! NILP (result))
3507 return unbind_to (count, result); 3507 return unbind_to (count, result);
3508 } 3508 }
@@ -3667,16 +3667,17 @@ substitute_in_interval (INTERVAL interval, void *arg)
3667} 3667}
3668 3668
3669 3669
3670/* Convert STRING to a number, assuming base BASE. Return a fixnum if 3670/* Convert STRING to a number, assuming base BASE. When STRING has
3671 STRING has integer syntax and fits in a fixnum, else return the 3671 floating point syntax and BASE is 10, return a nearest float. When
3672 nearest float if STRING has either floating point or integer syntax 3672 STRING has integer syntax, return a fixnum if the integer fits, and
3673 and BASE is 10, else return nil. If IGNORE_TRAILING, consider just 3673 signal an overflow otherwise (unless BASE is 10 and STRING ends in
3674 the longest prefix of STRING that has valid floating point syntax. 3674 period or FLAGS & S2N_OVERFLOW_TO_FLOAT is nonzero; in this case,
3675 Signal an overflow if BASE is not 10 and the number has integer 3675 return a nearest float instead). Otherwise, return nil. If FLAGS
3676 syntax but does not fit. */ 3676 & S2N_IGNORE_TRAILING is nonzero, consider just the longest prefix
3677 of STRING that has valid syntax. */
3677 3678
3678Lisp_Object 3679Lisp_Object
3679string_to_number (char const *string, int base, bool ignore_trailing) 3680string_to_number (char const *string, int base, int flags)
3680{ 3681{
3681 char const *cp = string; 3682 char const *cp = string;
3682 bool float_syntax = 0; 3683 bool float_syntax = 0;
@@ -3759,9 +3760,10 @@ string_to_number (char const *string, int base, bool ignore_trailing)
3759 || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP)); 3760 || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP));
3760 } 3761 }
3761 3762
3762 /* Return nil if the number uses invalid syntax. If IGNORE_TRAILING, accept 3763 /* Return nil if the number uses invalid syntax. If FLAGS &
3763 any prefix that matches. Otherwise, the entire string must match. */ 3764 S2N_IGNORE_TRAILING, accept any prefix that matches. Otherwise,
3764 if (! (ignore_trailing 3765 the entire string must match. */
3766 if (! (flags & S2N_IGNORE_TRAILING
3765 ? ((state & LEAD_INT) != 0 || float_syntax) 3767 ? ((state & LEAD_INT) != 0 || float_syntax)
3766 : (!*cp && ((state & ~(INTOVERFLOW | DOT_CHAR)) == LEAD_INT 3768 : (!*cp && ((state & ~(INTOVERFLOW | DOT_CHAR)) == LEAD_INT
3767 || float_syntax)))) 3769 || float_syntax))))
@@ -3776,7 +3778,7 @@ string_to_number (char const *string, int base, bool ignore_trailing)
3776 /* Unfortunately there's no simple and accurate way to convert 3778 /* Unfortunately there's no simple and accurate way to convert
3777 non-base-10 numbers that are out of C-language range. */ 3779 non-base-10 numbers that are out of C-language range. */
3778 if (base != 10) 3780 if (base != 10)
3779 xsignal1 (Qoverflow_error, build_string (string)); 3781 flags = 0;
3780 } 3782 }
3781 else if (n <= (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM)) 3783 else if (n <= (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM))
3782 { 3784 {
@@ -3785,6 +3787,9 @@ string_to_number (char const *string, int base, bool ignore_trailing)
3785 } 3787 }
3786 else 3788 else
3787 value = n; 3789 value = n;
3790
3791 if (! (state & DOT_CHAR) && ! (flags & S2N_OVERFLOW_TO_FLOAT))
3792 xsignal1 (Qoverflow_error, build_string (string));
3788 } 3793 }
3789 3794
3790 /* Either the number uses float syntax, or it does not fit into a fixnum. 3795 /* Either the number uses float syntax, or it does not fit into a fixnum.
diff --git a/src/process.c b/src/process.c
index 2aaa238f60c..ed2cab7b51f 100644
--- a/src/process.c
+++ b/src/process.c
@@ -6842,7 +6842,7 @@ SIGCODE may be an integer, or a symbol whose name is a signal name. */)
6842 { 6842 {
6843 Lisp_Object tem = Fget_process (process); 6843 Lisp_Object tem = Fget_process (process);
6844 if (NILP (tem)) 6844 if (NILP (tem))
6845 tem = string_to_number (SSDATA (process), 10, true); 6845 tem = string_to_number (SSDATA (process), 10, S2N_OVERFLOW_TO_FLOAT);
6846 process = tem; 6846 process = tem;
6847 } 6847 }
6848 else if (!NUMBERP (process)) 6848 else if (!NUMBERP (process))
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index 6e1f730166d..442ad089375 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -142,27 +142,41 @@
142 (should (string-equal (format "%#05X" #x10) "0X010")) 142 (should (string-equal (format "%#05X" #x10) "0X010"))
143 (should (string-equal (format "%#04x" 0) "0000"))) 143 (should (string-equal (format "%#04x" 0) "0000")))
144 144
145;;; Test Bug#30408. 145
146;;; Tests for Bug#30408.
147
146(ert-deftest format-%d-large-float () 148(ert-deftest format-%d-large-float ()
147 (should (string-equal (format "%d" 18446744073709551616.0) 149 (should (string-equal (format "%d" 18446744073709551616.0)
148 "18446744073709551616")) 150 "18446744073709551616"))
149 (should (string-equal (format "%d" -18446744073709551616.0) 151 (should (string-equal (format "%d" -18446744073709551616.0)
150 "-18446744073709551616"))) 152 "-18446744073709551616")))
151 153
152;;; Another test for Bug#30408.
153;;; Perhaps Emacs will be improved someday to return the correct 154;;; Perhaps Emacs will be improved someday to return the correct
154;;; answer for positive numbers instead of overflowing; in 155;;; answer for positive numbers instead of overflowing; in
155;;; that case this test will need to be changed. In the meantime make 156;;; that case these tests will need to be changed. In the meantime make
156;;; sure Emacs is reporting the overflow correctly. 157;;; sure Emacs is reporting the overflow correctly.
157(ert-deftest format-%x-large-float () 158(ert-deftest format-%x-large-float ()
158 (should-error (format "%x" 18446744073709551616.0) 159 (should-error (format "%x" 18446744073709551616.0)
159 :type 'overflow-error)) 160 :type 'overflow-error))
161(ert-deftest read-large-integer ()
162 (should-error (read (format "%d0" most-negative-fixnum))
163 :type 'overflow-error)
164 (should-error (read (format "%+d" (* -8.0 most-negative-fixnum)))
165 :type 'overflow-error)
166 (should-error (read (substring (format "%d" most-negative-fixnum) 1))
167 :type 'overflow-error)
168 (should-error (read (format "#x%x" most-negative-fixnum))
169 :type 'overflow-error)
170 (should-error (read (format "#o%o" most-negative-fixnum))
171 :type 'overflow-error)
172 (should-error (read (format "#32rG%x" most-positive-fixnum))
173 :type 'overflow-error))
160 174
161;;; Another test for Bug#30408.
162(ert-deftest format-%o-invalid-float () 175(ert-deftest format-%o-invalid-float ()
163 (should-error (format "%o" -1e-37) 176 (should-error (format "%o" -1e-37)
164 :type 'overflow-error)) 177 :type 'overflow-error))
165 178
179
166;;; Check format-time-string with various TZ settings. 180;;; Check format-time-string with various TZ settings.
167;;; Use only POSIX-compatible TZ values, since the tests should work 181;;; Use only POSIX-compatible TZ values, since the tests should work
168;;; even if tzdb is not in use. 182;;; even if tzdb is not in use.