diff options
| author | Paul Eggert | 2018-08-17 00:25:20 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-08-17 00:26:19 -0700 |
| commit | 64eb9b71da7c3c34541929c1b0dfb7f0c11d3d88 (patch) | |
| tree | 0b905edf417cb3e62706d84e5776a2a26065453f /src | |
| parent | 3b9017b5ba6b7041fbf70691092533286cc9b98d (diff) | |
| download | emacs-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.c | 23 | ||||
| -rw-r--r-- | src/data.c | 6 | ||||
| -rw-r--r-- | src/lisp.h | 13 |
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 | |||
| 3807 | void | ||
| 3808 | mpz_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, ...); | |||
| 3559 | extern Lisp_Object make_bignum_str (const char *num, int base); | 3559 | extern Lisp_Object make_bignum_str (const char *num, int base); |
| 3560 | extern Lisp_Object make_number (mpz_t value); | 3560 | extern Lisp_Object make_number (mpz_t value); |
| 3561 | extern void mpz_set_intmax_slow (mpz_t result, intmax_t v); | 3561 | extern void mpz_set_intmax_slow (mpz_t result, intmax_t v); |
| 3562 | extern void mpz_set_uintmax_slow (mpz_t result, uintmax_t v); | ||
| 3563 | 3562 | ||
| 3564 | INLINE void | 3563 | INLINE void |
| 3565 | mpz_set_intmax (mpz_t result, intmax_t v) | 3564 | mpz_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 | ||
| 3576 | INLINE void | ||
| 3577 | mpz_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 | ||
| 3590 | INLINE Lisp_Object | 3577 | INLINE Lisp_Object |