aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorPaul Eggert2018-08-21 02:16:50 -0700
committerPaul Eggert2018-08-21 02:38:53 -0700
commitd6a497dd887cdbb35c5b4e2929e83962ba708159 (patch)
tree9f0441f9fe88419b71e568b05ef7f7bea0a0ff06 /src/alloc.c
parent77fc2725985b4e5ef977ae6930835c7f0771c61c (diff)
downloademacs-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.c73
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)
3746Lisp_Object 3746Lisp_Object
3747make_number (mpz_t value) 3747make_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
7205void
7206integer_overflow (void)
7207{
7208 error ("Integer too large to be represented");
7209}
7210
7211static void *
7212xrealloc_for_gmp (void *ptr, size_t ignore, size_t size)
7213{
7214 return xrealloc (ptr, size);
7215}
7216
7217static void
7218xfree_for_gmp (void *ptr, size_t ignore)
7219{
7220 xfree (ptr);
7221}
7222
7203/* Initialization. */ 7223/* Initialization. */
7204 7224
7205void 7225void
@@ -7233,6 +7253,10 @@ init_alloc_once (void)
7233void 7253void
7234init_alloc (void) 7254init_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.
7364Integers outside the fixnum range are limited to absolute values less
7365than 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);