summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2010-08-04 14:25:17 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2010-08-04 14:25:17 +0000
commit607a3b70f0558c422d9be56060d136b33628280d (patch)
tree0fa7c6f0c9c9226de6c41b1a69804fba1b804ec2
parent7da56181323a6581c0de457c5687356645cfd8a7 (diff)
downloadmpfr-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.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/get_sj.c b/get_sj.c
index f1aa22917..4921520b0 100644
--- a/get_sj.c
+++ b/get_sj.c
@@ -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)));