aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2011-04-21 11:57:37 -0700
committerPaul Eggert2011-04-21 11:57:37 -0700
commitd78050d6bab1f1add4284163b8fc474495ac6580 (patch)
tree19bafdabc58b1758fa4f240bd63a2da402502546
parent452f4150134e4ba7bbd2bad9ce87d19c200505de (diff)
downloademacs-d78050d6bab1f1add4284163b8fc474495ac6580.tar.gz
emacs-d78050d6bab1f1add4284163b8fc474495ac6580.zip
* lread.c (string_to_number): Use strtoumax, to convert more integers without overflow.
-rw-r--r--src/ChangeLog7
-rw-r--r--src/lread.c60
2 files changed, 34 insertions, 33 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 2b9978f3d6a..0ea90a4d8e5 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -11,7 +11,8 @@
11 parsing non-base-10 numbers, as the documentation specifies. 11 parsing non-base-10 numbers, as the documentation specifies.
12 * lisp.h (string_to_number): New decl, replacing ... 12 * lisp.h (string_to_number): New decl, replacing ...
13 (isfloat_string): Remove. 13 (isfloat_string): Remove.
14 * lread.c (read1): Do not accept +. and -. as integers; this 14 * lread.c: Include <inttypes.h>, for uintmax_t and strtoimax.
15 (read1): Do not accept +. and -. as integers; this
15 appears to have been a coding error. Similarly, do not accept 16 appears to have been a coding error. Similarly, do not accept
16 strings like +-1e0 as floating point numbers. Do not report 17 strings like +-1e0 as floating point numbers. Do not report
17 overflow for integer overflows unless the base is not 10 which 18 overflow for integer overflows unless the base is not 10 which
@@ -25,7 +26,9 @@
25 (string_to_number): New function, replacing isfloat_string. 26 (string_to_number): New function, replacing isfloat_string.
26 This function checks for valid syntax and produces the resulting 27 This function checks for valid syntax and produces the resulting
27 Lisp float number too. Rework it so that string-to-number 28 Lisp float number too. Rework it so that string-to-number
28 no longer mishandles examples like "1.0e+". 29 no longer mishandles examples like "1.0e+". Use strtoimax,
30 so that overflow for non-base-10 numbers is reported only when
31 there's no portable and simple way to convert to floating point.
29 32
302011-04-20 Paul Eggert <eggert@cs.ucla.edu> 332011-04-20 Paul Eggert <eggert@cs.ucla.edu>
31 34
diff --git a/src/lread.c b/src/lread.c
index 390c57d1678..531fee3fa3b 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -19,6 +19,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19 19
20 20
21#include <config.h> 21#include <config.h>
22#include <inttypes.h>
22#include <stdio.h> 23#include <stdio.h>
23#include <sys/types.h> 24#include <sys/types.h>
24#include <sys/stat.h> 25#include <sys/stat.h>
@@ -3226,7 +3227,6 @@ string_to_number (char const *string, int base, int ignore_trailing)
3226 ++cp; 3227 ++cp;
3227 while (0 <= digit_to_number (*cp, base)); 3228 while (0 <= digit_to_number (*cp, base));
3228 } 3229 }
3229
3230 if (*cp == '.') 3230 if (*cp == '.')
3231 { 3231 {
3232 state |= DOT_CHAR; 3232 state |= DOT_CHAR;
@@ -3300,47 +3300,45 @@ string_to_number (char const *string, int base, int ignore_trailing)
3300 : (!*cp && ((state & ~DOT_CHAR) == LEAD_INT || float_syntax)))) 3300 : (!*cp && ((state & ~DOT_CHAR) == LEAD_INT || float_syntax))))
3301 return Qnil; 3301 return Qnil;
3302 3302
3303 /* If the number does not use float syntax, and fits into a fixnum, return 3303 /* If the number uses integer and not float syntax, and is in C-language
3304 the fixnum. */ 3304 range, use its value, preferably as a fixnum. */
3305 if (0 <= leading_digit && ! float_syntax) 3305 if (0 <= leading_digit && ! float_syntax)
3306 { 3306 {
3307 /* Convert string to EMACS_INT. Do not use strtol, to avoid assuming 3307 uintmax_t n;
3308 that EMACS_INT is no wider than 'long', and because when BASE is 16 3308
3309 strtol might accept numbers like "0x1" that are not allowed here. */ 3309 /* Fast special case for single-digit integers. This also avoids a
3310 EMACS_INT n = leading_digit; 3310 glitch when BASE is 16 and IGNORE_TRAILING is nonzero, because in that
3311 EMACS_INT abs_bound = 3311 case some versions of strtoumax accept numbers like "0x1" that Emacs
3312 (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM); 3312 does not allow. */
3313 EMACS_INT abs_bound_over_base = abs_bound / base; 3313 if (digit_to_number (string[signedp + 1], base) < 0)
3314 3314 return make_number (negative ? -leading_digit : leading_digit);
3315 for (cp = string + signedp + 1; ; cp++) 3315
3316 errno = 0;
3317 n = strtoumax (string + signedp, NULL, base);
3318 if (errno == ERANGE)
3316 { 3319 {
3317 int d = digit_to_number (*cp, base); 3320 /* Unfortunately there's no simple and accurate way to convert
3318 if (d < 0) 3321 non-base-10 numbers that are out of C-language range. */
3319 { 3322 if (base != 10)
3320 if (n <= abs_bound) 3323 xsignal (Qoverflow_error, list1 (build_string (string)));
3321 return make_number (negative ? -n : n);
3322 break;
3323 }
3324 if (abs_bound_over_base < n)
3325 break;
3326 n = base * n + d;
3327 } 3324 }
3328 3325 else if (n <= (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM))
3329 /* Unfortunately there's no simple and reliable way to convert 3326 {
3330 non-base-10 to floating point. */ 3327 EMACS_INT signed_n = n;
3331 if (base != 10) 3328 return make_number (negative ? -signed_n : signed_n);
3332 xsignal (Qoverflow_error, list1 (build_string (string))); 3329 }
3330 else
3331 value = n;
3333 } 3332 }
3334 3333
3335 /* Either the number uses float syntax, or it does not fit into a fixnum. 3334 /* Either the number uses float syntax, or it does not fit into a fixnum.
3336 Convert it from string to floating point, unless the value is already 3335 Convert it from string to floating point, unless the value is already
3337 known because it is an infinity or a NAN. */ 3336 known because it is an infinity, a NAN, or its absolute value fits in
3337 uintmax_t. */
3338 if (! value) 3338 if (! value)
3339 value = atof (string + signedp); 3339 value = atof (string + signedp);
3340 3340
3341 if (negative) 3341 return make_float (negative ? -value : value);
3342 value = -value;
3343 return make_float (value);
3344} 3342}
3345 3343
3346 3344