about summary refs log tree commit diff
path: root/stdlib/strtod_l.c
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 /stdlib/strtod_l.c
parentae75a883f2eb312165d1e1f423cea320f3c92ef5 (diff)
downloadglibc-4406c41c1d6088abf01c216e49700cd3f8f01fcc.tar.gz
glibc-4406c41c1d6088abf01c216e49700cd3f8f01fcc.tar.xz
glibc-4406c41c1d6088abf01c216e49700cd3f8f01fcc.zip
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.
Diffstat (limited to 'stdlib/strtod_l.c')
-rw-r--r--stdlib/strtod_l.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index 6707e482a4..3c449c7d54 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);
 	}