diff options
| author | Paul Eggert | 2018-03-29 10:16:29 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-03-29 11:03:07 -0700 |
| commit | 6b3d01dad415230ad0bd0d01a05351d7a8b0e8c3 (patch) | |
| tree | d49bf4520d6afc830aa9d016be3d57349b251c4f /src | |
| parent | 3409fe0362c52127c52f854a7300f4dde4b8fffe (diff) | |
| download | emacs-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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/data.c | 9 | ||||
| -rw-r--r-- | src/lisp.h | 3 | ||||
| -rw-r--r-- | src/lread.c | 35 | ||||
| -rw-r--r-- | src/process.c | 2 |
4 files changed, 27 insertions, 22 deletions
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). | |||
| 2716 | If the base used is not 10, STRING is always parsed as an integer. */) | 2716 | If 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 | } |
| 3900 | extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, | 3900 | extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, |
| 3901 | Lisp_Object *, Lisp_Object, bool); | 3901 | Lisp_Object *, Lisp_Object, bool); |
| 3902 | extern Lisp_Object string_to_number (char const *, int, bool); | 3902 | enum { S2N_IGNORE_TRAILING = 1, S2N_OVERFLOW_TO_FLOAT = 2 }; |
| 3903 | extern Lisp_Object string_to_number (char const *, int, int); | ||
| 3903 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), | 3904 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), |
| 3904 | Lisp_Object); | 3905 | Lisp_Object); |
| 3905 | extern void dir_warning (const char *, Lisp_Object); | 3906 | extern 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 | ||
| 3678 | Lisp_Object | 3679 | Lisp_Object |
| 3679 | string_to_number (char const *string, int base, bool ignore_trailing) | 3680 | string_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)) |