diff -Naurd mpfr-4.1.0-a/PATCHES mpfr-4.1.0-b/PATCHES --- mpfr-4.1.0-a/PATCHES 2021-02-11 12:46:49.075316772 +0000 +++ mpfr-4.1.0-b/PATCHES 2021-02-11 12:46:49.115316335 +0000 @@ -0,0 +1 @@ +set_z_2exp-overflow diff -Naurd mpfr-4.1.0-a/VERSION mpfr-4.1.0-b/VERSION --- mpfr-4.1.0-a/VERSION 2021-02-11 12:43:51.801257430 +0000 +++ mpfr-4.1.0-b/VERSION 2021-02-11 12:46:49.115316335 +0000 @@ -1 +1 @@ -4.1.0-p2 +4.1.0-p3 diff -Naurd mpfr-4.1.0-a/src/mpfr.h mpfr-4.1.0-b/src/mpfr.h --- mpfr-4.1.0-a/src/mpfr.h 2021-02-11 12:43:51.801257430 +0000 +++ mpfr-4.1.0-b/src/mpfr.h 2021-02-11 12:46:49.115316335 +0000 @@ -27,7 +27,7 @@ #define MPFR_VERSION_MAJOR 4 #define MPFR_VERSION_MINOR 1 #define MPFR_VERSION_PATCHLEVEL 0 -#define MPFR_VERSION_STRING "4.1.0-p2" +#define MPFR_VERSION_STRING "4.1.0-p3" /* User macros: MPFR_USE_FILE: Define it to make MPFR define functions dealing diff -Naurd mpfr-4.1.0-a/src/set_z_exp.c mpfr-4.1.0-b/src/set_z_exp.c --- mpfr-4.1.0-a/src/set_z_exp.c 2020-01-08 18:11:13.000000000 +0000 +++ mpfr-4.1.0-b/src/set_z_exp.c 2021-02-11 12:46:49.103316466 +0000 @@ -28,10 +28,11 @@ int mpfr_set_z_2exp (mpfr_ptr f, mpz_srcptr z, mpfr_exp_t e, mpfr_rnd_t rnd_mode) { - mp_size_t fn, zn, dif, en; + mp_size_t fn, zn, dif; int k, sign_z, inex; mp_limb_t *fp, *zp; - mpfr_exp_t exp; + mpfr_exp_t exp, nmax; + mpfr_uexp_t uexp; sign_z = mpz_sgn (z); if (MPFR_UNLIKELY (sign_z == 0)) /* ignore the exponent for 0 */ @@ -43,10 +44,15 @@ MPFR_ASSERTD (sign_z == MPFR_SIGN_POS || sign_z == MPFR_SIGN_NEG); zn = ABSIZ(z); /* limb size of z */ - /* compute en = floor(e/GMP_NUMB_BITS) */ - en = (e >= 0) ? e / GMP_NUMB_BITS : (e + 1) / GMP_NUMB_BITS - 1; MPFR_ASSERTD (zn >= 1); - if (MPFR_UNLIKELY (zn + en > MPFR_EMAX_MAX / GMP_NUMB_BITS + 1)) + nmax = MPFR_EMAX_MAX / GMP_NUMB_BITS + 1; + /* Detect early overflow with zn + en > nmax, + where en = floor(e / GMP_NUMB_BITS). + This is checked without an integer overflow (even assuming some + future version of GMP, where limitations may be removed). */ + if (MPFR_UNLIKELY (e >= 0 ? + zn > nmax - e / GMP_NUMB_BITS : + zn + (e + 1) / GMP_NUMB_BITS - 1 > nmax)) return mpfr_overflow (f, rnd_mode, sign_z); /* because zn + en >= MPFR_EMAX_MAX / GMP_NUMB_BITS + 2 implies (zn + en) * GMP_NUMB_BITS >= MPFR_EMAX_MAX + GMP_NUMB_BITS + 1 @@ -64,8 +70,21 @@ and exp = zn * GMP_NUMB_BITS + e - k <= (zn + en) * GMP_NUMB_BITS - k + GMP_NUMB_BITS - 1 <= MPFR_EMAX_MAX + 2 * GMP_NUMB_BITS - 1 */ - exp = (mpfr_prec_t) zn * GMP_NUMB_BITS + e - k; + /* We need to compute exp = zn * GMP_NUMB_BITS + e - k with well-defined + operations (no integer overflows / no implementation-defined results). + The mathematical result of zn * GMP_NUMB_BITS may be larger than + the largest value of mpfr_exp_t while exp could still be less than + __gmpfr_emax. Thanks to early overflow detection, we can compute the + result in modular arithmetic, using mpfr_uexp_t, and convert it to + mpfr_exp_t. */ + uexp = (mpfr_uexp_t) zn * GMP_NUMB_BITS + (mpfr_uexp_t) e - k; + + /* Convert to signed in a portable way (see doc/README.dev). + On most platforms, this can be optimized to identity (no-op). */ + exp = uexp > MPFR_EXP_MAX ? -1 - (mpfr_exp_t) ~uexp : (mpfr_exp_t) uexp; + /* The exponent will be exp or exp + 1 (due to rounding) */ + if (MPFR_UNLIKELY (exp > __gmpfr_emax)) return mpfr_overflow (f, rnd_mode, sign_z); if (MPFR_UNLIKELY (exp + 1 < __gmpfr_emin)) diff -Naurd mpfr-4.1.0-a/src/version.c mpfr-4.1.0-b/src/version.c --- mpfr-4.1.0-a/src/version.c 2021-02-11 12:43:51.801257430 +0000 +++ mpfr-4.1.0-b/src/version.c 2021-02-11 12:46:49.115316335 +0000 @@ -25,5 +25,5 @@ const char * mpfr_get_version (void) { - return "4.1.0-p2"; + return "4.1.0-p3"; } diff -Naurd mpfr-4.1.0-a/tests/tset_z_exp.c mpfr-4.1.0-b/tests/tset_z_exp.c --- mpfr-4.1.0-a/tests/tset_z_exp.c 2020-01-08 18:11:13.000000000 +0000 +++ mpfr-4.1.0-b/tests/tset_z_exp.c 2021-02-11 12:46:49.103316466 +0000 @@ -97,49 +97,149 @@ mpfr_get_si is a rather indirect test of a low level routine. */ static void -check (long i, mpfr_rnd_t rnd) +check (long i, mpfr_rnd_t rnd, int reduced) { - mpfr_t f; + mpfr_t f1, f2, f3; mpz_t z; - mpfr_exp_t e; + mpfr_exp_t e, old_emin, old_emax; int inex; + mpfr_flags_t flags; + + old_emin = mpfr_get_emin (); + old_emax = mpfr_get_emax (); /* using CHAR_BIT * sizeof(long) bits of precision ensures that mpfr_set_z_2exp is exact below */ - mpfr_init2 (f, CHAR_BIT * sizeof(long)); + mpfr_inits2 (CHAR_BIT * sizeof(long), f1, f2, f3, (mpfr_ptr) 0); mpz_init (z); mpz_set_ui (z, i); /* the following loop ensures that no overflow occurs */ do e = randexp (); while (e > mpfr_get_emax () - CHAR_BIT * sizeof(long)); - inex = mpfr_set_z_2exp (f, z, e, rnd); - if (inex != 0) + + mpfr_clear_flags (); + inex = mpfr_set_z_2exp (f1, z, e, rnd); + flags = __gmpfr_flags; + + if (inex != 0 || flags != 0 || + (mpfr_div_2si (f2, f1, e, rnd), mpfr_get_si (f2, MPFR_RNDZ) != i)) { - printf ("Error in mpfr_set_z_2exp for i=%ld, e=%ld," - " wrong ternary value\n", i, (long) e); - printf ("expected 0, got %d\n", inex); + printf ("Error in mpfr_set_z_2exp for i=%ld e=%" MPFR_EXP_FSPEC + "d rnd_mode=%d\n", i, (mpfr_eexp_t) e, rnd); + mpfr_set_si_2exp (f2, i, e, MPFR_RNDN); + printf ("expected "); mpfr_dump (f2); + printf ("with inex = %d and flags =", 0); + flags_out (0); + printf ("got "); mpfr_dump (f1); + printf ("with inex = %d and flags =", inex); + flags_out (flags); exit (1); } - mpfr_div_2si (f, f, e, rnd); - if (mpfr_get_si (f, MPFR_RNDZ) != i) + + if (reduced) { - printf ("Error in mpfr_set_z_2exp for i=%ld e=", i); - if (e < LONG_MIN) - printf ("( LONG_MAX) - printf ("(>LONG_MAX)"); - else - printf ("%ld", (long) e); - printf (" rnd_mode=%d\n", rnd); - printf ("expected %ld\n", i); - printf ("got "); mpfr_dump (f); - exit (1); + mpfr_exp_t ef, emin, emax; + int inex2, inex3; + mpfr_flags_t flags2, flags3; + + ef = i == 0 ? 0 : mpfr_get_exp (f1); + for (emin = ef - 2; emin <= ef + 2; emin++) + for (emax = emin; emax <= ef + 2; emax++) + { + inex3 = mpfr_set (f3, f1, rnd); + MPFR_ASSERTN (inex3 == 0); + mpfr_set_emin (emin); + mpfr_set_emax (emax); + mpfr_clear_flags (); + inex2 = mpfr_set_z_2exp (f2, z, e, rnd); + flags2 = __gmpfr_flags; + mpfr_clear_flags (); + inex3 = mpfr_check_range (f3, 0, rnd); + flags3 = __gmpfr_flags; + if (!(mpfr_equal_p (f2, f3) && + SAME_SIGN (inex2, inex3) && + flags2 == flags3)) + { + printf ("Error in mpfr_set_z_2exp for i=%ld e=%" + MPFR_EXP_FSPEC "d rnd_mode=%d\nand emin=%" + MPFR_EXP_FSPEC "d emax=%" MPFR_EXP_FSPEC + "d\n", i, (mpfr_eexp_t) e, rnd, + (mpfr_eexp_t) emin, (mpfr_eexp_t) emax); + printf ("expected "); mpfr_dump (f3); + printf ("with inex = %d and flags =", inex3); + flags_out (flags3); + printf ("got "); mpfr_dump (f2); + printf ("with inex = %d and flags =", inex2); + flags_out (flags2); + exit (1); + } + } + mpfr_set_emin (old_emin); + mpfr_set_emax (old_emax); } - mpfr_clear (f); + + mpfr_clears (f1, f2, f3, (mpfr_ptr) 0); mpz_clear (z); } +static void +check_huge (void) +{ + if (getenv ("MPFR_CHECK_LARGEMEM") != NULL) + { + mpfr_t x; + mpz_t z; + long e; + + /* Increase tests_memory_limit to the maximum in order to avoid + an obvious failure due to insufficient memory. */ + tests_memory_limit = (size_t) -1; /* no memory limit */ + + mpfr_init2 (x, 32); + + /* In r14140, with a 32-bit ABI (GCC's -m32): + - With UBsan (-fsanitize=undefined -fno-sanitize-recover), + this fails with: + set_z_2exp.c:71:26: runtime error: signed integer overflow: + 67108864 * 32 cannot be represented in type 'long int' + - With -D_MPFR_EXP_FORMAT=4, this fails with: + Expected 0.10001000000000000000000000000000E5 + Got 0 + */ + mpz_init_set_ui (z, 17); + e = 0x7ffffff0; + mpz_mul_2exp (z, z, e); + mpz_add_ui (z, z, 1); + mpfr_set_z_2exp (x, z, -e, MPFR_RNDN); + if (mpfr_cmp_ui0 (x, 17) != 0) + { + printf ("Error 1 in check_huge\n"); + printf ("Expected 0.10001000000000000000000000000000E5\n"); + printf ("Got "); + mpfr_dump (x); + exit (1); + } + mpz_clear (z); + + mpz_init_set_ui (z, 17); + mpz_mul_2exp (z, z, 0xffffffb0); + mpz_add_ui (z, z, 1); + mpfr_set_z_2exp (x, z, -1, MPFR_RNDN); + if (! MPFR_IS_INF (x) || MPFR_IS_NEG (x)) + { + printf ("Error 2 in check_huge\n"); + printf ("Expected @Inf@\n"); + printf ("Got "); + mpfr_dump (x); + exit (1); + } + mpz_clear (z); + + mpfr_clear (x); + } +} + int main (int argc, char *argv[]) { @@ -147,11 +247,13 @@ tests_start_mpfr (); - check (0, MPFR_RNDN); + check (0, MPFR_RNDN, 0); for (j = 0; j < 200000; j++) - check (randlimb () & LONG_MAX, RND_RAND ()); + check (randlimb () & LONG_MAX, RND_RAND (), j < 200); check0 (); + check_huge (); + tests_end_mpfr (); return 0;