diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2010-08-04 14:25:17 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2010-08-04 14:25:17 +0000 |
commit | 607a3b70f0558c422d9be56060d136b33628280d (patch) | |
tree | 0fa7c6f0c9c9226de6c41b1a69804fba1b804ec2 | |
parent | 7da56181323a6581c0de457c5687356645cfd8a7 (diff) | |
download | mpfr-607a3b70f0558c422d9be56060d136b33628280d.tar.gz |
[get_sj.c] Fixed bug found by John Regehr:
https://gforge.inria.fr/tracker/index.php?func=detail&aid=10839&group_id=136&atid=619
Note: the problem was an undefined behavior that could occur when
sizeof(mp_limb_t) < sizeof(intmax_t) and |x| was small enough,
because a right shift was >= the type width. However as the shifted
value was 0, most platforms should not be affected by this bug. This
problem was detected with clang -fcatch-undefined-ansic-behavior.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@7047 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | get_sj.c | 15 |
1 files changed, 10 insertions, 5 deletions
@@ -94,7 +94,12 @@ mpfr_get_sj (mpfr_srcptr f, mpfr_rnd_t rnd) } else if (MPFR_IS_POS (x)) { - for (n = MPFR_LIMB_SIZE (x) - 1; n >= 0; n--) + /* Note: testing the condition sh >= 0 is necessary to avoid + an undefined behavior on xp[n] >> S when S >= GMP_NUMB_BITS + (even though xp[n] == 0 in such a case). This can happen if + sizeof(mp_limb_t) < sizeof(intmax_t) and |x| is small enough + because of the trailing bits due to its normalization. */ + for (n = MPFR_LIMB_SIZE (x) - 1; n >= 0 && sh >= 0; n--) { sh -= GMP_NUMB_BITS; /* Note the concerning the casts below: @@ -104,7 +109,7 @@ mpfr_get_sj (mpfr_srcptr f, mpfr_rnd_t rnd) for the case sizeof(intmax_t) == sizeof(mp_limb_t), as mp_limb_t is unsigned, therefore not representable as an intmax_t when the MSB is 1 (this is the case here). */ - MPFR_ASSERTD (-sh < GMP_NUMB_BITS); + MPFR_ASSERTD (sh < GMP_NUMB_BITS && -sh < GMP_NUMB_BITS); r += (sh >= 0 ? (intmax_t) xp[n] << sh : (intmax_t) (xp[n] >> (-sh))); @@ -112,11 +117,11 @@ mpfr_get_sj (mpfr_srcptr f, mpfr_rnd_t rnd) } else { - for (n = MPFR_LIMB_SIZE (x) - 1; n >= 0; n--) + /* See the comments for the case x positive. */ + for (n = MPFR_LIMB_SIZE (x) - 1; n >= 0 && sh >= 0; n--) { sh -= GMP_NUMB_BITS; - /* See above for the note concerning the casts. */ - MPFR_ASSERTD (-sh < GMP_NUMB_BITS); + MPFR_ASSERTD (sh < GMP_NUMB_BITS && -sh < GMP_NUMB_BITS); r -= (sh >= 0 ? (intmax_t) xp[n] << sh : (intmax_t) (xp[n] >> (-sh))); |