diff options
| author | Paul Eggert | 2018-08-21 02:16:50 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-08-21 02:38:53 -0700 |
| commit | d6a497dd887cdbb35c5b4e2929e83962ba708159 (patch) | |
| tree | 9f0441f9fe88419b71e568b05ef7f7bea0a0ff06 /src/alloc.c | |
| parent | 77fc2725985b4e5ef977ae6930835c7f0771c61c (diff) | |
| download | emacs-d6a497dd887cdbb35c5b4e2929e83962ba708159.tar.gz emacs-d6a497dd887cdbb35c5b4e2929e83962ba708159.zip | |
Avoid libgmp aborts by imposing limits
libgmp calls ‘abort’ when given numbers too big for its
internal data structures. The numeric limit is large and
platform-dependent; with 64-bit GMP 6.1.2 it is around
2**2**37. Work around the problem by refusing to call libgmp
functions with arguments that would cause an abort. With luck
libgmp will have a better way to do this in the future.
Also, introduce a variable integer-width that lets the user
control how large bignums can be. This currently defaults
to 2**16, i.e., it allows bignums up to 2**2**16. This
should be enough for ordinary computation, and should
help Emacs to avoid thrashing or hanging.
Problem noted by Pip Cet (Bug#32463#71).
* doc/lispref/numbers.texi, etc/NEWS:
Document recent bignum changes, including this one.
Improve documentation for bitwise operations, in the light
of bignums.
* src/alloc.c (make_number): Enforce integer-width.
(integer_overflow): New function.
(xrealloc_for_gmp, xfree_for_gmp):
Move here from emacs.c, as it's memory allocation.
(init_alloc): Initialize GMP here, rather than in emacs.c.
(integer_width): New var.
* src/data.c (GMP_NLIMBS_MAX, NLIMBS_LIMIT): New constants.
(emacs_mpz_size, emacs_mpz_mul)
(emacs_mpz_mul_2exp, emacs_mpz_pow_ui): New functions.
(arith_driver, Fash, expt_integer): Use them.
(expt_integer): New function, containing integer code
that was out of place in floatfns.c.
(check_bignum_size, xmalloc_for_gmp): Remove.
* src/emacs.c (main): Do not initialize GMP here.
* src/floatfns.c (Fexpt): Use expt_integer, which
now contains integer code moved from here.
* src/lisp.h (GMP_NUMB_BITS): Define if gmp.h doesn’t.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 73 |
1 files changed, 51 insertions, 22 deletions
diff --git a/src/alloc.c b/src/alloc.c index ddc0696ba91..24a24aab96b 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3746,33 +3746,33 @@ make_bignum_str (const char *num, int base) | |||
| 3746 | Lisp_Object | 3746 | Lisp_Object |
| 3747 | make_number (mpz_t value) | 3747 | make_number (mpz_t value) |
| 3748 | { | 3748 | { |
| 3749 | if (mpz_fits_slong_p (value)) | 3749 | size_t bits = mpz_sizeinbase (value, 2); |
| 3750 | { | 3750 | |
| 3751 | long l = mpz_get_si (value); | 3751 | if (bits <= FIXNUM_BITS) |
| 3752 | if (!FIXNUM_OVERFLOW_P (l)) | ||
| 3753 | return make_fixnum (l); | ||
| 3754 | } | ||
| 3755 | else if (LONG_WIDTH < FIXNUM_BITS) | ||
| 3756 | { | 3752 | { |
| 3757 | size_t bits = mpz_sizeinbase (value, 2); | 3753 | EMACS_INT v = 0; |
| 3754 | int i = 0, shift = 0; | ||
| 3758 | 3755 | ||
| 3759 | if (bits <= FIXNUM_BITS) | 3756 | do |
| 3760 | { | 3757 | { |
| 3761 | EMACS_INT v = 0; | 3758 | EMACS_INT limb = mpz_getlimbn (value, i++); |
| 3762 | int i = 0; | 3759 | v += limb << shift; |
| 3763 | for (int shift = 0; shift < bits; shift += mp_bits_per_limb) | 3760 | shift += GMP_NUMB_BITS; |
| 3764 | { | 3761 | } |
| 3765 | EMACS_INT limb = mpz_getlimbn (value, i++); | 3762 | while (shift < bits); |
| 3766 | v += limb << shift; | ||
| 3767 | } | ||
| 3768 | if (mpz_sgn (value) < 0) | ||
| 3769 | v = -v; | ||
| 3770 | 3763 | ||
| 3771 | if (!FIXNUM_OVERFLOW_P (v)) | 3764 | if (mpz_sgn (value) < 0) |
| 3772 | return make_fixnum (v); | 3765 | v = -v; |
| 3773 | } | 3766 | |
| 3767 | if (!FIXNUM_OVERFLOW_P (v)) | ||
| 3768 | return make_fixnum (v); | ||
| 3774 | } | 3769 | } |
| 3775 | 3770 | ||
| 3771 | /* The documentation says integer-width should be nonnegative, so | ||
| 3772 | a single comparison suffices even though 'bits' is unsigned. */ | ||
| 3773 | if (integer_width < bits) | ||
| 3774 | integer_overflow (); | ||
| 3775 | |||
| 3776 | struct Lisp_Bignum *b = ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum, value, | 3776 | struct Lisp_Bignum *b = ALLOCATE_PSEUDOVECTOR (struct Lisp_Bignum, value, |
| 3777 | PVEC_BIGNUM); | 3777 | PVEC_BIGNUM); |
| 3778 | /* We could mpz_init + mpz_swap here, to avoid a copy, but the | 3778 | /* We could mpz_init + mpz_swap here, to avoid a copy, but the |
| @@ -7200,6 +7200,26 @@ verify_alloca (void) | |||
| 7200 | 7200 | ||
| 7201 | #endif /* ENABLE_CHECKING && USE_STACK_LISP_OBJECTS */ | 7201 | #endif /* ENABLE_CHECKING && USE_STACK_LISP_OBJECTS */ |
| 7202 | 7202 | ||
| 7203 | /* Memory allocation for GMP. */ | ||
| 7204 | |||
| 7205 | void | ||
| 7206 | integer_overflow (void) | ||
| 7207 | { | ||
| 7208 | error ("Integer too large to be represented"); | ||
| 7209 | } | ||
| 7210 | |||
| 7211 | static void * | ||
| 7212 | xrealloc_for_gmp (void *ptr, size_t ignore, size_t size) | ||
| 7213 | { | ||
| 7214 | return xrealloc (ptr, size); | ||
| 7215 | } | ||
| 7216 | |||
| 7217 | static void | ||
| 7218 | xfree_for_gmp (void *ptr, size_t ignore) | ||
| 7219 | { | ||
| 7220 | xfree (ptr); | ||
| 7221 | } | ||
| 7222 | |||
| 7203 | /* Initialization. */ | 7223 | /* Initialization. */ |
| 7204 | 7224 | ||
| 7205 | void | 7225 | void |
| @@ -7233,6 +7253,10 @@ init_alloc_once (void) | |||
| 7233 | void | 7253 | void |
| 7234 | init_alloc (void) | 7254 | init_alloc (void) |
| 7235 | { | 7255 | { |
| 7256 | eassert (mp_bits_per_limb == GMP_NUMB_BITS); | ||
| 7257 | integer_width = 1 << 16; | ||
| 7258 | mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp); | ||
| 7259 | |||
| 7236 | Vgc_elapsed = make_float (0.0); | 7260 | Vgc_elapsed = make_float (0.0); |
| 7237 | gcs_done = 0; | 7261 | gcs_done = 0; |
| 7238 | 7262 | ||
| @@ -7335,6 +7359,11 @@ The time is in seconds as a floating point value. */); | |||
| 7335 | DEFVAR_INT ("gcs-done", gcs_done, | 7359 | DEFVAR_INT ("gcs-done", gcs_done, |
| 7336 | doc: /* Accumulated number of garbage collections done. */); | 7360 | doc: /* Accumulated number of garbage collections done. */); |
| 7337 | 7361 | ||
| 7362 | DEFVAR_INT ("integer-width", integer_width, | ||
| 7363 | doc: /* Maximum number of bits in bignums. | ||
| 7364 | Integers outside the fixnum range are limited to absolute values less | ||
| 7365 | than 2**N, where N is this variable's value. N should be nonnegative. */); | ||
| 7366 | |||
| 7338 | defsubr (&Scons); | 7367 | defsubr (&Scons); |
| 7339 | defsubr (&Slist); | 7368 | defsubr (&Slist); |
| 7340 | defsubr (&Svector); | 7369 | defsubr (&Svector); |