1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00

Fix strtod handling of underflow (bug 14047).

This commit is contained in:
Joseph Myers
2012-10-30 13:51:27 +00:00
parent e5088dc687
commit 2a27fd6dae
21 changed files with 434 additions and 13 deletions

View File

@ -62,6 +62,7 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
#include <string.h>
#include <stdint.h>
#include <rounding-mode.h>
#include <tininess.h>
/* The gmp headers need some configuration frobs. */
#define HAVE_ALLOCA 1
@ -209,12 +210,15 @@ static FLOAT
round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
mp_limb_t round_limb, mp_size_t round_bit, int more_bits)
{
int mode = get_rounding_mode ();
if (exponent < MIN_EXP - 1)
{
if (exponent < MIN_EXP - 1 - MANT_DIG)
return underflow_value (negative);
mp_size_t shift = MIN_EXP - 1 - exponent;
bool is_tiny = true;
more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
if (shift == MANT_DIG)
@ -248,6 +252,33 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
}
else if (shift > 0)
{
if (TININESS_AFTER_ROUNDING && shift == 1)
{
/* Whether the result counts as tiny depends on whether,
after rounding to the normal precision, it still has
a subnormal exponent. */
mp_limb_t retval_normal[RETURN_LIMB_SIZE];
if (round_away (negative,
(retval[0] & 1) != 0,
(round_limb
& (((mp_limb_t) 1) << round_bit)) != 0,
(more_bits
|| ((round_limb
& ((((mp_limb_t) 1) << round_bit) - 1))
!= 0)),
mode))
{
mp_limb_t cy = __mpn_add_1 (retval_normal, retval,
RETURN_LIMB_SIZE, 1);
if (((MANT_DIG % BITS_PER_MP_LIMB) == 0 && cy) ||
((MANT_DIG % BITS_PER_MP_LIMB) != 0 &&
((retval_normal[RETURN_LIMB_SIZE - 1]
& (((mp_limb_t) 1) << (MANT_DIG % BITS_PER_MP_LIMB)))
!= 0)))
is_tiny = false;
}
}
round_limb = retval[0];
round_bit = shift - 1;
(void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
@ -259,14 +290,20 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
# define DENORM_EXP (MIN_EXP - 2)
#endif
exponent = DENORM_EXP;
__set_errno (ERANGE);
if (is_tiny
&& ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0
|| more_bits
|| (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0))
{
__set_errno (ERANGE);
volatile FLOAT force_underflow_exception = MIN_VALUE * MIN_VALUE;
(void) force_underflow_exception;
}
}
if (exponent > MAX_EXP)
goto overflow;
int mode = get_rounding_mode ();
if (round_away (negative,
(retval[0] & 1) != 0,
(round_limb & (((mp_limb_t) 1) << round_bit)) != 0,