diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2020-03-09 15:31:45 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2020-03-09 15:31:45 +0000 |
commit | d2a6160bd4e9ca6c9d8a4e99cdfc27a8f6ae18f7 (patch) | |
tree | 20628f47fae99fbd6a03f47a64380d21a56508d9 | |
parent | 679d3a89f72f2cb188369e387dfaf9ee3fccc1bb (diff) | |
download | mpfr-d2a6160bd4e9ca6c9d8a4e99cdfc27a8f6ae18f7.tar.gz |
[src/eint.c] Bug fix: possible integer overflow with some
C implementations (or some _MPFR_PREC_FORMAT / _MPFR_EXP_FORMAT values)
due to the use of incorrect integer types.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@13758 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | src/eint.c | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/src/eint.c b/src/eint.c index 796999d65..4df65821d 100644 --- a/src/eint.c +++ b/src/eint.c @@ -31,7 +31,8 @@ https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., */ /* Compute in y an approximation of sum(x^k/k/k!, k=1..infinity), - and return e such that the absolute error is bound by 2^e ulp(y). + assuming x != 0, and return e such that the absolute error is + bounded by 2^e ulp(y). Return PREC(y) when the truncated series does not converge. */ static mpfr_exp_t @@ -65,21 +66,32 @@ mpfr_eint_aux (mpfr_t y, mpfr_srcptr x) mpz_init (u); mpz_init (m); MPFR_GROUP_INIT_3 (group, 31, eps, erru, errs); - e = mpfr_get_z_2exp (m, x); /* x = m * 2^e */ + e = mpfr_get_z_2exp (m, x); /* x = m * 2^e with m != 0 */ MPFR_LOG_MSG (("e=%" MPFR_EXP_FSPEC "d\n", (mpfr_eexp_t) e)); - MPFR_ASSERTD (mpz_sizeinbase (m, 2) == MPFR_PREC (x)); + MPFR_ASSERTD (mpz_sizeinbase (m, 2) == MPFR_PREC (x)); /* since m != 0 */ if (MPFR_PREC (x) > w) { e += MPFR_PREC (x) - w; - mpz_tdiv_q_2exp (m, m, MPFR_PREC (x) - w); + mpz_tdiv_q_2exp (m, m, MPFR_PREC (x) - w); /* one still has m != 0 */ MPFR_LOG_MSG (("e=%" MPFR_EXP_FSPEC "d\n", (mpfr_eexp_t) e)); } - MPFR_LOG_MSG (("m %s 0\n", mpz_sgn (m) != 0 ? "!=" : "==")); - /* remove trailing zeroes from m: this will speed up much cases where - x is a small integer divided by a power of 2 */ - k = mpz_scan1 (m, 0); - mpz_tdiv_q_2exp (m, m, k); - e += k; + /* Remove trailing zeroes from m: this will speed up much cases where + x is a small integer divided by a power of 2. + Note: As shown above, m != 0. This is needed for the "e += ..." below, + otherwise n would take the largest value of mp_bitcnt_t and could be + too large. */ + { + mp_bitcnt_t n = mpz_scan1 (m, 0); + mpz_tdiv_q_2exp (m, m, n); + /* Since one initially has mpz_sizeinbase (m, 2) == MPFR_PREC (x) + and m has not increased, one can deduce that n <= MPFR_PREC (x), + so that the cast to mpfr_prec_t is valid. This cast is needed to + ensure that the operand e of the addition below is not converted + to an unsigned integer type, which could yield incorrect results + with some C implementations. */ + MPFR_ASSERTD (n <= MPFR_PREC (x)); + e += (mpfr_prec_t) n; + } /* initialize t to 2^w */ mpz_set_ui (t, 1); mpz_mul_2exp (t, t, w); |