summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2020-03-09 15:31:45 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2020-03-09 15:31:45 +0000
commitd2a6160bd4e9ca6c9d8a4e99cdfc27a8f6ae18f7 (patch)
tree20628f47fae99fbd6a03f47a64380d21a56508d9
parent679d3a89f72f2cb188369e387dfaf9ee3fccc1bb (diff)
downloadmpfr-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.c32
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);