aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2018-08-17 00:25:20 -0700
committerPaul Eggert2018-08-17 00:26:19 -0700
commit64eb9b71da7c3c34541929c1b0dfb7f0c11d3d88 (patch)
tree0b905edf417cb3e62706d84e5776a2a26065453f /src
parent3b9017b5ba6b7041fbf70691092533286cc9b98d (diff)
downloademacs-64eb9b71da7c3c34541929c1b0dfb7f0c11d3d88.tar.gz
emacs-64eb9b71da7c3c34541929c1b0dfb7f0c11d3d88.zip
Fix problems with logxor etc. and fixnums
These operations incorrectly treated negative fixnums as bignums greater than most-positive-fixnum. * src/alloc.c (mpz_set_intmax_slow): Avoid undefined behavior if signed unary negation overflows, while we’re in the neighborhood. (mpz_set_uintmax_slow): Remove. All uses removed. * src/data.c (arith_driver): Treat fixnums as signed, not unsigned, even for logical operations. * src/lisp.h (mpz_set_uintmax): Remove. All uses removed. * test/src/data-tests.el (data-tests-logand) (data-tests-logior, data-tests-logxor): New tests.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c23
-rw-r--r--src/data.c6
-rw-r--r--src/lisp.h13
3 files changed, 9 insertions, 33 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 6a938211599..0cd3f0c0c3b 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3793,28 +3793,17 @@ mpz_set_intmax_slow (mpz_t result, intmax_t v)
3793 /* If long is larger then a faster path is taken. */ 3793 /* If long is larger then a faster path is taken. */
3794 eassert (sizeof (intmax_t) > sizeof (long)); 3794 eassert (sizeof (intmax_t) > sizeof (long));
3795 3795
3796 bool negate = false; 3796 bool complement = v < 0;
3797 if (v < 0) 3797 if (complement)
3798 { 3798 v = -1 - v;
3799 v = -v;
3800 negate = true;
3801 }
3802 mpz_set_uintmax_slow (result, (uintmax_t) v);
3803 if (negate)
3804 mpz_neg (result, result);
3805}
3806
3807void
3808mpz_set_uintmax_slow (mpz_t result, uintmax_t v)
3809{
3810 /* If long is larger then a faster path is taken. */
3811 eassert (sizeof (uintmax_t) > sizeof (unsigned long));
3812 3799
3813 /* COUNT = 1 means just a single word of the given size. ORDER = -1 3800 /* COUNT = 1 means just a single word of the given size. ORDER = -1
3814 is arbitrary since there's only a single word. ENDIAN = 0 means 3801 is arbitrary since there's only a single word. ENDIAN = 0 means
3815 use the native endian-ness. NAILS = 0 means use the whole 3802 use the native endian-ness. NAILS = 0 means use the whole
3816 word. */ 3803 word. */
3817 mpz_import (result, 1, -1, sizeof (uintmax_t), 0, 0, &v); 3804 mpz_import (result, 1, -1, sizeof v, 0, 0, &v);
3805 if (complement)
3806 mpz_com (result, result);
3818} 3807}
3819 3808
3820 3809
diff --git a/src/data.c b/src/data.c
index 66f508c8f43..5a355d9787c 100644
--- a/src/data.c
+++ b/src/data.c
@@ -3006,7 +3006,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
3006 { 3006 {
3007 mpz_t tem; 3007 mpz_t tem;
3008 mpz_init (tem); 3008 mpz_init (tem);
3009 mpz_set_uintmax (tem, XUFIXNUM (val)); 3009 mpz_set_intmax (tem, XFIXNUM (val));
3010 mpz_and (accum, accum, tem); 3010 mpz_and (accum, accum, tem);
3011 mpz_clear (tem); 3011 mpz_clear (tem);
3012 } 3012 }
@@ -3018,7 +3018,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
3018 { 3018 {
3019 mpz_t tem; 3019 mpz_t tem;
3020 mpz_init (tem); 3020 mpz_init (tem);
3021 mpz_set_uintmax (tem, XUFIXNUM (val)); 3021 mpz_set_intmax (tem, XFIXNUM (val));
3022 mpz_ior (accum, accum, tem); 3022 mpz_ior (accum, accum, tem);
3023 mpz_clear (tem); 3023 mpz_clear (tem);
3024 } 3024 }
@@ -3030,7 +3030,7 @@ arith_driver (enum arithop code, ptrdiff_t nargs, Lisp_Object *args)
3030 { 3030 {
3031 mpz_t tem; 3031 mpz_t tem;
3032 mpz_init (tem); 3032 mpz_init (tem);
3033 mpz_set_uintmax (tem, XUFIXNUM (val)); 3033 mpz_set_intmax (tem, XFIXNUM (val));
3034 mpz_xor (accum, accum, tem); 3034 mpz_xor (accum, accum, tem);
3035 mpz_clear (tem); 3035 mpz_clear (tem);
3036 } 3036 }
diff --git a/src/lisp.h b/src/lisp.h
index da93efdd934..f2cfe81ca75 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3559,7 +3559,6 @@ extern Lisp_Object listn (enum constype, ptrdiff_t, Lisp_Object, ...);
3559extern Lisp_Object make_bignum_str (const char *num, int base); 3559extern Lisp_Object make_bignum_str (const char *num, int base);
3560extern Lisp_Object make_number (mpz_t value); 3560extern Lisp_Object make_number (mpz_t value);
3561extern void mpz_set_intmax_slow (mpz_t result, intmax_t v); 3561extern void mpz_set_intmax_slow (mpz_t result, intmax_t v);
3562extern void mpz_set_uintmax_slow (mpz_t result, uintmax_t v);
3563 3562
3564INLINE void 3563INLINE void
3565mpz_set_intmax (mpz_t result, intmax_t v) 3564mpz_set_intmax (mpz_t result, intmax_t v)
@@ -3573,18 +3572,6 @@ mpz_set_intmax (mpz_t result, intmax_t v)
3573 mpz_set_si (result, v); 3572 mpz_set_si (result, v);
3574} 3573}
3575 3574
3576INLINE void
3577mpz_set_uintmax (mpz_t result, uintmax_t v)
3578{
3579 /* mpz_set_ui works in terms of unsigned long, but Emacs may use a
3580 wider integer type, and so sometimes will have to construct the
3581 mpz_t by hand. */
3582 if (sizeof (uintmax_t) > sizeof (unsigned long) && (unsigned long) v != v)
3583 mpz_set_uintmax_slow (result, v);
3584 else
3585 mpz_set_ui (result, v);
3586}
3587
3588/* Build a frequently used 2/3/4-integer lists. */ 3575/* Build a frequently used 2/3/4-integer lists. */
3589 3576
3590INLINE Lisp_Object 3577INLINE Lisp_Object