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.
This commit is contained in:
Aurelien Jarno 2014-05-20 14:41:44 +02:00
parent ae75a883f2
commit 4406c41c1d
3 changed files with 13 additions and 4 deletions

View File

@ -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]

2
NEWS
View File

@ -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.

View File

@ -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);
}