aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2014-05-20 14:41:44 +0200
committerAurelien Jarno <aurelien@aurel32.net>2014-05-20 18:44:28 +0200
commit4406c41c1d6088abf01c216e49700cd3f8f01fcc (patch)
tree6f257fdf8bf4d27212a380a049548f24cdf7f389
parentae75a883f2eb312165d1e1f423cea320f3c92ef5 (diff)
downloadglibc-4406c41c1d6088abf01c216e49700cd3f8f01fcc.zip
glibc-4406c41c1d6088abf01c216e49700cd3f8f01fcc.tar.gz
glibc-4406c41c1d6088abf01c216e49700cd3f8f01fcc.tar.bz2
Fix strtold on 32-bit sparc (and probably others) (BZ #16965)
This patch fixes an issue observed running the tst-strtod-round test on 32 bit sparc. In some conditions, strtold calls round_and_return, which in turn calls __mpn_rshift with cnt = 0, while stdlib/rshift.c explicitly says that cnts should satisfy 0 < CNT < BITS_PER_MP_LIMB. In this case, the code end up doing a logical shift right of the same amount than the register, which is undefined in the C standard. Due to this bug, 32-bit sparc does not correctly convert the value "0x1p-16446", but it is likely that other architectures are also affected for other input values.
-rw-r--r--ChangeLog4
-rw-r--r--NEWS2
-rw-r--r--stdlib/strtod_l.c11
3 files changed, 13 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 59464a6..e87fc22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,10 @@
* localedata/tst-langinfo.sh: Send output to stdout.
* localedata/tst-langinfo-static.c: New file.
+ [BZ #16965]
+ * stdlib/strtod_l.c (round_and_return): Add code to shift limbs
+ when the shift amount is modulo the limb size.
+
2014-05-20 Richard Henderson <rth@redhat.com>
[BZ #16967]
diff --git a/NEWS b/NEWS
index d9ce8f9..8aaf2f4 100644
--- a/NEWS
+++ b/NEWS
@@ -18,7 +18,7 @@ Version 2.20
16760, 16770, 16786, 16789, 16791, 16799, 16800, 16815, 16823, 16824,
16831, 16838, 16849, 16854, 16876, 16877, 16885, 16888, 16890, 16912,
16915, 16916, 16917, 16922, 16927, 16928, 16932, 16943, 16958, 16966,
- 16967.
+ 16967, 16965.
* The minimum Linux kernel version that this version of the GNU C Library
can be used with is 2.6.32.
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index 6707e48..3c449c7 100644
--- a/stdlib/strtod_l.c
+++ b/stdlib/strtod_l.c
@@ -243,9 +243,14 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
more_bits |= ((round_limb & ((((mp_limb_t) 1) << round_bit) - 1))
!= 0);
- (void) __mpn_rshift (retval, &retval[shift / BITS_PER_MP_LIMB],
- RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB),
- shift % BITS_PER_MP_LIMB);
+ /* __mpn_rshift requires 0 < shift < BITS_PER_MP_LIMB. */
+ if ((shift % BITS_PER_MP_LIMB) != 0)
+ (void) __mpn_rshift (retval, &retval[shift / BITS_PER_MP_LIMB],
+ RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB),
+ shift % BITS_PER_MP_LIMB);
+ else
+ for (i = 0; i < RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB); i++)
+ retval[i] = retval[i + (shift / BITS_PER_MP_LIMB)];
MPN_ZERO (&retval[RETURN_LIMB_SIZE - (shift / BITS_PER_MP_LIMB)],
shift / BITS_PER_MP_LIMB);
}