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_MIN)");
-      else if (e > 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;
