diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2011-06-06 01:29:01 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2011-06-06 01:29:01 -0700 |
commit | be44ca6cd47bff4cb0dfcfd71aa14f10fdab5434 (patch) | |
tree | 34110ed6783c1314604f3382e8cd6d0812b939e3 /src/data.c | |
parent | d1f3d2afe1057a99b9dec6d1bd5b57bfee81fdff (diff) | |
download | emacs-be44ca6cd47bff4cb0dfcfd71aa14f10fdab5434.tar.gz |
Check for overflow when converting integer to cons and back.
* charset.c (Fdefine_charset_internal, Fdecode_char):
Use cons_to_unsigned to catch overflow.
(Fencode_char): Use INTEGER_TO_CONS.
* composite.h (LGLYPH_CODE): Use cons_to_unsigned.
(LGLYPH_SET_CODE): Use INTEGER_TO_CONS.
* data.c (long_to_cons, cons_to_long): Remove.
(cons_to_unsigned, cons_to_signed): New functions.
These signal an error for invalid or out-of-range values.
* dired.c (Ffile_attributes): Use INTEGER_TO_CONS.
* fileio.c (Fset_visited_file_modtime): Use CONS_TO_INTEGER.
* font.c (Ffont_variation_glyphs):
* fontset.c (Finternal_char_font): Use INTEGER_TO_CONS.
* lisp.h: Include <intprops.h>.
(INTEGER_TO_CONS, CONS_TO_INTEGER): New macros.
(cons_to_signed, cons_to_unsigned): New decls.
(long_to_cons, cons_to_long): Remove decls.
* undo.c (record_first_change): Use INTEGER_TO_CONS.
(Fprimitive_undo): Use CONS_TO_INTEGER.
* xfns.c (Fx_window_property): Likewise.
* xselect.c: Include <limits.h>.
(x_own_selection, selection_data_to_lisp_data):
Use INTEGER_TO_CONS.
(x_handle_selection_request, x_handle_selection_clear)
(x_get_foreign_selection, Fx_disown_selection_internal)
(Fx_get_atom_name, x_send_client_event): Use CONS_TO_INTEGER.
(lisp_data_to_selection_data): Use cons_to_unsigned.
(x_fill_property_data): Use cons_to_signed.
Report values out of range.
Diffstat (limited to 'src/data.c')
-rw-r--r-- | src/data.c | 121 |
1 files changed, 99 insertions, 22 deletions
diff --git a/src/data.c b/src/data.c index 78bd454056d..a41ffe7a1f6 100644 --- a/src/data.c +++ b/src/data.c @@ -2326,33 +2326,110 @@ DEFUN ("zerop", Fzerop, Szerop, 1, 1, 0, return Qnil; } -/* Convert between long values and pairs of Lisp integers. - Note that long_to_cons returns a single Lisp integer - when the value fits in one. */ +/* Convert the cons-of-integers, integer, or float value C to an + unsigned value with maximum value MAX. Signal an error if C does not + have a valid format or is out of range. */ +uintmax_t +cons_to_unsigned (Lisp_Object c, uintmax_t max) +{ + int valid = 0; + uintmax_t val IF_LINT (= 0); + if (INTEGERP (c)) + { + valid = 0 <= XINT (c); + val = XINT (c); + } + else if (FLOATP (c)) + { + double d = XFLOAT_DATA (c); + if (0 <= d + && d < (max == UINTMAX_MAX ? (double) UINTMAX_MAX + 1 : max + 1)) + { + val = d; + valid = 1; + } + } + else if (CONSP (c) && NATNUMP (XCAR (c))) + { + uintmax_t top = XFASTINT (XCAR (c)); + Lisp_Object rest = XCDR (c); + if (top <= UINTMAX_MAX >> 24 >> 16 + && CONSP (rest) + && NATNUMP (XCAR (rest)) && XFASTINT (XCAR (rest)) < 1 << 24 + && NATNUMP (XCDR (rest)) && XFASTINT (XCDR (rest)) < 1 << 16) + { + uintmax_t mid = XFASTINT (XCAR (rest)); + val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); + valid = 1; + } + else if (top <= UINTMAX_MAX >> 16) + { + if (CONSP (rest)) + rest = XCAR (rest); + if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) + { + val = top << 16 | XFASTINT (rest); + valid = 1; + } + } + } -Lisp_Object -long_to_cons (long unsigned int i) -{ - unsigned long top = i >> 16; - unsigned int bot = i & 0xFFFF; - if (top == 0) - return make_number (bot); - if (top == (unsigned long)-1 >> 16) - return Fcons (make_number (-1), make_number (bot)); - return Fcons (make_number (top), make_number (bot)); + if (! (valid && val <= max)) + error ("Not an in-range integer, float, or cons of integers"); + return val; } -unsigned long -cons_to_long (Lisp_Object c) +/* Convert the cons-of-integers, integer, or float value C to a signed + value with extrema MIN and MAX. Signal an error if C does not have + a valid format or is out of range. */ +intmax_t +cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) { - Lisp_Object top, bot; + int valid = 0; + intmax_t val IF_LINT (= 0); if (INTEGERP (c)) - return XINT (c); - top = XCAR (c); - bot = XCDR (c); - if (CONSP (bot)) - bot = XCAR (bot); - return ((XINT (top) << 16) | XINT (bot)); + { + val = XINT (c); + valid = 1; + } + else if (FLOATP (c)) + { + double d = XFLOAT_DATA (c); + if (min <= d + && d < (max == INTMAX_MAX ? (double) INTMAX_MAX + 1 : max + 1)) + { + val = d; + valid = 1; + } + } + else if (CONSP (c) && INTEGERP (XCAR (c))) + { + intmax_t top = XINT (XCAR (c)); + Lisp_Object rest = XCDR (c); + if (INTMAX_MIN >> 24 >> 16 <= top && top <= INTMAX_MAX >> 24 >> 16 + && CONSP (rest) + && NATNUMP (XCAR (rest)) && XFASTINT (XCAR (rest)) < 1 << 24 + && NATNUMP (XCDR (rest)) && XFASTINT (XCDR (rest)) < 1 << 16) + { + intmax_t mid = XFASTINT (XCAR (rest)); + val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); + valid = 1; + } + else if (INTMAX_MIN >> 16 <= top && top <= INTMAX_MAX >> 16) + { + if (CONSP (rest)) + rest = XCAR (rest); + if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) + { + val = top << 16 | XFASTINT (rest); + valid = 1; + } + } + } + + if (! (valid && min <= val && val <= max)) + error ("Not an in-range integer, float, or cons of integers"); + return val; } DEFUN ("number-to-string", Fnumber_to_string, Snumber_to_string, 1, 1, 0, |