aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2018-10-10 23:17:18 -0700
committerPaul Eggert2018-10-10 23:19:42 -0700
commit5bd8cfc14d4b0c78c07e65a583f42a10c4cbc06d (patch)
treec51b2a470f62679f5e5c3f6f55d90aa0082d0133 /src
parentfd3a48fcd8bb212ec12b9b10a79de0ae605ee93b (diff)
downloademacs-5bd8cfc14d4b0c78c07e65a583f42a10c4cbc06d.tar.gz
emacs-5bd8cfc14d4b0c78c07e65a583f42a10c4cbc06d.zip
Fix mishandling of symbols that look like numbers
* src/bignum.c (make_neg_biguint): New function. * src/lread.c (read1): Do not mishandle an unquoted symbol with name equal to something like "1\0x", i.e., a string of numeric form followed by a NUL byte. Formerly these symbols were misread as numbers. (string_to_number): Change last argument from an integer flag to a pointer to the length. This lets the caller figure out how much of the prefix was used. All callers changed. Add a fast path if the integer (sans sign) fits in uintmax_t. Update comments and simplify now that bignums are present. * src/print.c (print_object): Fix quoting of symbols that look like numbers, by relying on string_to_number for the tricky cases rather than trying to redo its logic, incorrectly. For example, (read (prin1-to-string '\1e+NaN)) formerly returned "1e+NaN", which was wrong: a backslash is needed in the output to prevent it from being read as a NaN. Escape NO_BREAK_SPACE too, since lread.c treats it like SPACE. * test/src/print-tests.el (print-read-roundtrip): Add tests illustrating the abovementioned bugs.
Diffstat (limited to 'src')
-rw-r--r--src/bignum.c10
-rw-r--r--src/data.c2
-rw-r--r--src/lisp.h5
-rw-r--r--src/lread.c100
-rw-r--r--src/print.c49
-rw-r--r--src/process.c7
6 files changed, 85 insertions, 88 deletions
diff --git a/src/bignum.c b/src/bignum.c
index 0ab8de3ab7a..e3db0377a53 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -117,6 +117,16 @@ make_biguint (uintmax_t n)
117 return make_bignum (); 117 return make_bignum ();
118} 118}
119 119
120/* Return a Lisp integer equal to -N, which must not be in fixnum range. */
121Lisp_Object
122make_neg_biguint (uintmax_t n)
123{
124 eassert (-MOST_NEGATIVE_FIXNUM < n);
125 mpz_set_uintmax (mpz[0], n);
126 mpz_neg (mpz[0], mpz[0]);
127 return make_bignum ();
128}
129
120/* Return a Lisp integer with value taken from mpz[0]. 130/* Return a Lisp integer with value taken from mpz[0].
121 Set mpz[0] to a junk value. */ 131 Set mpz[0] to a junk value. */
122Lisp_Object 132Lisp_Object
diff --git a/src/data.c b/src/data.c
index 5f1d059512d..538081e5c9b 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2796,7 +2796,7 @@ If the base used is not 10, STRING is always parsed as an integer. */)
2796 while (*p == ' ' || *p == '\t') 2796 while (*p == ' ' || *p == '\t')
2797 p++; 2797 p++;
2798 2798
2799 Lisp_Object val = string_to_number (p, b, S2N_IGNORE_TRAILING); 2799 Lisp_Object val = string_to_number (p, b, 0);
2800 return NILP (val) ? make_fixnum (0) : val; 2800 return NILP (val) ? make_fixnum (0) : val;
2801} 2801}
2802 2802
diff --git a/src/lisp.h b/src/lisp.h
index 2c20b483cad..5ecc48b025c 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2506,7 +2506,7 @@ INTEGERP (Lisp_Object x)
2506 return FIXNUMP (x) || BIGNUMP (x); 2506 return FIXNUMP (x) || BIGNUMP (x);
2507} 2507}
2508 2508
2509/* Return a Lisp integer with value taken from n. */ 2509/* Return a Lisp integer with value taken from N. */
2510INLINE Lisp_Object 2510INLINE Lisp_Object
2511make_int (intmax_t n) 2511make_int (intmax_t n)
2512{ 2512{
@@ -3329,6 +3329,7 @@ extern ptrdiff_t bignum_bufsize (Lisp_Object, int);
3329extern ptrdiff_t bignum_to_c_string (char *, ptrdiff_t, Lisp_Object, int); 3329extern ptrdiff_t bignum_to_c_string (char *, ptrdiff_t, Lisp_Object, int);
3330extern Lisp_Object bignum_to_string (Lisp_Object, int); 3330extern Lisp_Object bignum_to_string (Lisp_Object, int);
3331extern Lisp_Object make_bignum_str (char const *, int); 3331extern Lisp_Object make_bignum_str (char const *, int);
3332extern Lisp_Object make_neg_biguint (uintmax_t);
3332extern Lisp_Object double_to_integer (double); 3333extern Lisp_Object double_to_integer (double);
3333 3334
3334/* Converthe integer NUM to *N. Return true if successful, false 3335/* Converthe integer NUM to *N. Return true if successful, false
@@ -3839,7 +3840,7 @@ LOADHIST_ATTACH (Lisp_Object x)
3839extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, 3840extern int openp (Lisp_Object, Lisp_Object, Lisp_Object,
3840 Lisp_Object *, Lisp_Object, bool); 3841 Lisp_Object *, Lisp_Object, bool);
3841enum { S2N_IGNORE_TRAILING = 1 }; 3842enum { S2N_IGNORE_TRAILING = 1 };
3842extern Lisp_Object string_to_number (char const *, int, int); 3843extern Lisp_Object string_to_number (char const *, int, ptrdiff_t *);
3843extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), 3844extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
3844 Lisp_Object); 3845 Lisp_Object);
3845extern void dir_warning (const char *, Lisp_Object); 3846extern void dir_warning (const char *, Lisp_Object);
diff --git a/src/lread.c b/src/lread.c
index 73e38d89954..62616cb6819 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2354,12 +2354,14 @@ character_name_to_code (char const *name, ptrdiff_t name_len)
2354{ 2354{
2355 /* For "U+XXXX", pass the leading '+' to string_to_number to reject 2355 /* For "U+XXXX", pass the leading '+' to string_to_number to reject
2356 monstrosities like "U+-0000". */ 2356 monstrosities like "U+-0000". */
2357 ptrdiff_t len = name_len - 1;
2357 Lisp_Object code 2358 Lisp_Object code
2358 = (name[0] == 'U' && name[1] == '+' 2359 = (name[0] == 'U' && name[1] == '+'
2359 ? string_to_number (name + 1, 16, 0) 2360 ? string_to_number (name + 1, 16, &len)
2360 : call2 (Qchar_from_name, make_unibyte_string (name, name_len), Qt)); 2361 : call2 (Qchar_from_name, make_unibyte_string (name, name_len), Qt));
2361 2362
2362 if (! RANGED_FIXNUMP (0, code, MAX_UNICODE_CHAR) 2363 if (! RANGED_FIXNUMP (0, code, MAX_UNICODE_CHAR)
2364 || len != name_len - 1
2363 || char_surrogate_p (XFIXNUM (code))) 2365 || char_surrogate_p (XFIXNUM (code)))
2364 { 2366 {
2365 AUTO_STRING (format, "\\N{%s}"); 2367 AUTO_STRING (format, "\\N{%s}");
@@ -3531,12 +3533,14 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3531 || strchr ("\"';()[]#`,", c) == NULL)); 3533 || strchr ("\"';()[]#`,", c) == NULL));
3532 3534
3533 *p = 0; 3535 *p = 0;
3536 ptrdiff_t nbytes = p - read_buffer;
3534 UNREAD (c); 3537 UNREAD (c);
3535 3538
3536 if (!quoted && !uninterned_symbol) 3539 if (!quoted && !uninterned_symbol)
3537 { 3540 {
3538 Lisp_Object result = string_to_number (read_buffer, 10, 0); 3541 ptrdiff_t len;
3539 if (! NILP (result)) 3542 Lisp_Object result = string_to_number (read_buffer, 10, &len);
3543 if (! NILP (result) && len == nbytes)
3540 return unbind_to (count, result); 3544 return unbind_to (count, result);
3541 } 3545 }
3542 if (!quoted && multibyte) 3546 if (!quoted && multibyte)
@@ -3548,7 +3552,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
3548 } 3552 }
3549 { 3553 {
3550 Lisp_Object result; 3554 Lisp_Object result;
3551 ptrdiff_t nbytes = p - read_buffer;
3552 ptrdiff_t nchars 3555 ptrdiff_t nchars
3553 = (multibyte 3556 = (multibyte
3554 ? multibyte_chars_in_text ((unsigned char *) read_buffer, 3557 ? multibyte_chars_in_text ((unsigned char *) read_buffer,
@@ -3700,18 +3703,18 @@ substitute_in_interval (INTERVAL interval, void *arg)
3700} 3703}
3701 3704
3702 3705
3703/* Convert STRING to a number, assuming base BASE. When STRING has 3706/* Convert the initial prefix of STRING to a number, assuming base BASE.
3704 floating point syntax and BASE is 10, return a nearest float. When 3707 If the prefix has floating point syntax and BASE is 10, return a
3705 STRING has integer syntax, return a fixnum if the integer fits, or 3708 nearest float; otherwise, if the prefix has integer syntax, return
3706 else a bignum. Otherwise, return nil. If FLAGS & 3709 the integer; otherwise, return nil. If PLEN, set *PLEN to the
3707 S2N_IGNORE_TRAILING is nonzero, consider just the longest prefix of 3710 length of the numeric prefix if there is one, otherwise *PLEN is
3708 STRING that has valid syntax. */ 3711 unspecified. */
3709 3712
3710Lisp_Object 3713Lisp_Object
3711string_to_number (char const *string, int base, int flags) 3714string_to_number (char const *string, int base, ptrdiff_t *plen)
3712{ 3715{
3713 char const *cp = string; 3716 char const *cp = string;
3714 bool float_syntax = 0; 3717 bool float_syntax = false;
3715 double value = 0; 3718 double value = 0;
3716 3719
3717 /* Negate the value ourselves. This treats 0, NaNs, and infinity properly on 3720 /* Negate the value ourselves. This treats 0, NaNs, and infinity properly on
@@ -3797,49 +3800,46 @@ string_to_number (char const *string, int base, int flags)
3797 || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP)); 3800 || (state & ~INTOVERFLOW) == (LEAD_INT|E_EXP));
3798 } 3801 }
3799 3802
3800 /* Return nil if the number uses invalid syntax. If FLAGS & 3803 if (plen)
3801 S2N_IGNORE_TRAILING, accept any prefix that matches. Otherwise, 3804 *plen = cp - string;
3802 the entire string must match. */
3803 if (! (flags & S2N_IGNORE_TRAILING
3804 ? ((state & LEAD_INT) != 0 || float_syntax)
3805 : (!*cp && ((state & ~(INTOVERFLOW | DOT_CHAR)) == LEAD_INT
3806 || float_syntax))))
3807 return Qnil;
3808 3805
3809 /* If the number uses integer and not float syntax, and is in C-language 3806 /* Return a float if the number uses float syntax. */
3810 range, use its value, preferably as a fixnum. */ 3807 if (float_syntax)
3811 if (leading_digit >= 0 && ! float_syntax)
3812 { 3808 {
3813 if ((state & INTOVERFLOW) == 0 3809 /* Convert to floating point, unless the value is already known
3814 && n <= (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM)) 3810 because it is infinite or a NaN. */
3815 { 3811 if (! value)
3816 EMACS_INT signed_n = n; 3812 value = atof (string + signedp);
3817 return make_fixnum (negative ? -signed_n : signed_n); 3813 return make_float (negative ? -value : value);
3818 }
3819
3820 /* Trim any leading "+" and trailing nondigits, then convert to
3821 bignum. */
3822 string += positive;
3823 if (!*after_digits)
3824 return make_bignum_str (string, base);
3825 ptrdiff_t trimmed_len = after_digits - string;
3826 USE_SAFE_ALLOCA;
3827 char *trimmed = SAFE_ALLOCA (trimmed_len + 1);
3828 memcpy (trimmed, string, trimmed_len);
3829 trimmed[trimmed_len] = '\0';
3830 Lisp_Object result = make_bignum_str (trimmed, base);
3831 SAFE_FREE ();
3832 return result;
3833 } 3814 }
3834 3815
3835 /* Either the number uses float syntax, or it does not fit into a fixnum. 3816 /* Return nil if the number uses invalid syntax. */
3836 Convert it from string to floating point, unless the value is already 3817 if (! (state & LEAD_INT))
3837 known because it is an infinity, a NAN, or its absolute value fits in 3818 return Qnil;
3838 uintmax_t. */ 3819
3839 if (! value) 3820 /* Fast path if the integer (san sign) fits in uintmax_t. */
3840 value = atof (string + signedp); 3821 if (! (state & INTOVERFLOW))
3822 {
3823 if (!negative)
3824 return make_uint (n);
3825 if (-MOST_NEGATIVE_FIXNUM < n)
3826 return make_neg_biguint (n);
3827 EMACS_INT signed_n = n;
3828 return make_fixnum (-signed_n);
3829 }
3841 3830
3842 return make_float (negative ? -value : value); 3831 /* Trim any leading "+" and trailing nondigits, then return a bignum. */
3832 string += positive;
3833 if (!*after_digits)
3834 return make_bignum_str (string, base);
3835 ptrdiff_t trimmed_len = after_digits - string;
3836 USE_SAFE_ALLOCA;
3837 char *trimmed = SAFE_ALLOCA (trimmed_len + 1);
3838 memcpy (trimmed, string, trimmed_len);
3839 trimmed[trimmed_len] = '\0';
3840 Lisp_Object result = make_bignum_str (trimmed, base);
3841 SAFE_FREE ();
3842 return result;
3843} 3843}
3844 3844
3845 3845
diff --git a/src/print.c b/src/print.c
index c0c90bc7e9a..d15ff97b00c 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1993,39 +1993,17 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
1993 1993
1994 case Lisp_Symbol: 1994 case Lisp_Symbol:
1995 { 1995 {
1996 bool confusing; 1996 Lisp_Object name = SYMBOL_NAME (obj);
1997 unsigned char *p = SDATA (SYMBOL_NAME (obj)); 1997 ptrdiff_t size_byte = SBYTES (name);
1998 unsigned char *end = p + SBYTES (SYMBOL_NAME (obj)); 1998
1999 int c; 1999 /* Set CONFUSING if NAME looks like a number, calling
2000 ptrdiff_t i, i_byte; 2000 string_to_number for non-obvious cases. */
2001 ptrdiff_t size_byte; 2001 char *p = SSDATA (name);
2002 Lisp_Object name; 2002 bool signedp = *p == '-' || *p == '+';
2003 2003 ptrdiff_t len;
2004 name = SYMBOL_NAME (obj); 2004 bool confusing = ((c_isdigit (p[signedp]) || p[signedp] == '.')
2005 2005 && !NILP (string_to_number (p, 10, &len))
2006 if (p != end && (*p == '-' || *p == '+')) p++; 2006 && len == size_byte);
2007 if (p == end)
2008 confusing = 0;
2009 /* If symbol name begins with a digit, and ends with a digit,
2010 and contains nothing but digits and `e', it could be treated
2011 as a number. So set CONFUSING.
2012
2013 Symbols that contain periods could also be taken as numbers,
2014 but periods are always escaped, so we don't have to worry
2015 about them here. */
2016 else if (*p >= '0' && *p <= '9'
2017 && end[-1] >= '0' && end[-1] <= '9')
2018 {
2019 while (p != end && ((*p >= '0' && *p <= '9')
2020 /* Needed for \2e10. */
2021 || *p == 'e' || *p == 'E'))
2022 p++;
2023 confusing = (end == p);
2024 }
2025 else
2026 confusing = 0;
2027
2028 size_byte = SBYTES (name);
2029 2007
2030 if (! NILP (Vprint_gensym) 2008 if (! NILP (Vprint_gensym)
2031 && !SYMBOL_INTERNED_IN_INITIAL_OBARRAY_P (obj)) 2009 && !SYMBOL_INTERNED_IN_INITIAL_OBARRAY_P (obj))
@@ -2036,10 +2014,12 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2036 break; 2014 break;
2037 } 2015 }
2038 2016
2039 for (i = 0, i_byte = 0; i_byte < size_byte;) 2017 ptrdiff_t i = 0;
2018 for (ptrdiff_t i_byte = 0; i_byte < size_byte; )
2040 { 2019 {
2041 /* Here, we must convert each multi-byte form to the 2020 /* Here, we must convert each multi-byte form to the
2042 corresponding character code before handing it to PRINTCHAR. */ 2021 corresponding character code before handing it to PRINTCHAR. */
2022 int c;
2043 FETCH_STRING_CHAR_ADVANCE (c, name, i, i_byte); 2023 FETCH_STRING_CHAR_ADVANCE (c, name, i, i_byte);
2044 maybe_quit (); 2024 maybe_quit ();
2045 2025
@@ -2049,6 +2029,7 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
2049 || c == ';' || c == '#' || c == '(' || c == ')' 2029 || c == ';' || c == '#' || c == '(' || c == ')'
2050 || c == ',' || c == '.' || c == '`' 2030 || c == ',' || c == '.' || c == '`'
2051 || c == '[' || c == ']' || c == '?' || c <= 040 2031 || c == '[' || c == ']' || c == '?' || c <= 040
2032 || c == NO_BREAK_SPACE
2052 || confusing 2033 || confusing
2053 || (i == 1 && confusable_symbol_character_p (c))) 2034 || (i == 1 && confusable_symbol_character_p (c)))
2054 { 2035 {
diff --git a/src/process.c b/src/process.c
index a9638dfc2df..6cda4f27acc 100644
--- a/src/process.c
+++ b/src/process.c
@@ -6852,7 +6852,12 @@ SIGCODE may be an integer, or a symbol whose name is a signal name. */)
6852 { 6852 {
6853 Lisp_Object tem = Fget_process (process); 6853 Lisp_Object tem = Fget_process (process);
6854 if (NILP (tem)) 6854 if (NILP (tem))
6855 tem = string_to_number (SSDATA (process), 10, 0); 6855 {
6856 ptrdiff_t len;
6857 tem = string_to_number (SSDATA (process), 10, &len);
6858 if (NILP (tem) || len != SBYTES (process))
6859 return Qnil;
6860 }
6856 process = tem; 6861 process = tem;
6857 } 6862 }
6858 else if (!NUMBERP (process)) 6863 else if (!NUMBERP (process))