summaryrefslogtreecommitdiff
path: root/src/data.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2011-06-06 01:29:01 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2011-06-06 01:29:01 -0700
commitbe44ca6cd47bff4cb0dfcfd71aa14f10fdab5434 (patch)
tree34110ed6783c1314604f3382e8cd6d0812b939e3 /src/data.c
parentd1f3d2afe1057a99b9dec6d1bd5b57bfee81fdff (diff)
downloademacs-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.c121
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,