Fix strtod subnormal rounding (bug 30220)

Message ID 8360e087-313-c9e-a4a3-613ce06d296c@redhat.com
State Committed
Commit 457622c2fa8f9f7435822d5287a437bc8be8090d
Delegated to: Adhemerval Zanella Netto
Headers
Series Fix strtod subnormal rounding (bug 30220) |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch fail Patch failed to apply to master at the time it was sent
redhat-pt-bot/TryBot-32bit fail Patch series failed to apply

Commit Message

Joseph Myers Aug. 16, 2024, 10:25 p.m. UTC
  As reported in bug 30220, the implementation of strtod-family
functions has a bug in the following case: the input string would,
with infinite exponent range, take one more bit to represent than is
available in the normal precision of the return type; the value
represented is in the subnormal range; and there are no nonzero bits
in the value, below those that can be represented in subnormal
precision, other than the least significant bit and possibly the
0.5ulp bit.  In this case, round_and_return ends up discarding the
least significant bit.

Fix by saving that bit to merge into more_bits (it can't be merged in
at the time it's computed, because more_bits mustn't include this bit
in the case of after-rounding tininess detection checking if the
result is still subnormal when rounded to normal precision, so merging
this bit into more_bits needs to take place after that check).

Tested for x86_64.

---

This patch is relative to a tree with
<https://sourceware.org/pipermail/libc-alpha/2024-August/159229.html>
(pending review) applied.  There is no logical dependency on that
patch; it's simply that both of them involve regenerating
tst-strtod-round-data.h.
  

Comments

Carlos O'Donell Aug. 19, 2024, 1:15 p.m. UTC | #1
On 8/16/24 6:25 PM, Joseph Myers wrote:
> This patch is relative to a tree with
> <https://sourceware.org/pipermail/libc-alpha/2024-August/159229.html>
> (pending review) applied.  There is no logical dependency on that
> patch; it's simply that both of them involve regenerating
> tst-strtod-round-data.h.

While there is no logical dependency, as a reviewer I want to try apply all of your
patches and review and test together to make my review more meaningful.

Would it be possible for you to post these together as a "loose" series that collects
everything for pre-commit CI to test and a reviewer to apply?
  
Joseph Myers Aug. 19, 2024, 3 p.m. UTC | #2
On Mon, 19 Aug 2024, Carlos O'Donell wrote:

> On 8/16/24 6:25 PM, Joseph Myers wrote:
> > This patch is relative to a tree with
> > <https://sourceware.org/pipermail/libc-alpha/2024-August/159229.html>
> > (pending review) applied.  There is no logical dependency on that
> > patch; it's simply that both of them involve regenerating
> > tst-strtod-round-data.h.
> 
> While there is no logical dependency, as a reviewer I want to try apply 
> all of your patches and review and test together to make my review more 
> meaningful.
> 
> Would it be possible for you to post these together as a "loose" series 
> that collects everything for pre-commit CI to test and a reviewer to 
> apply?

The "series" is ongoing in that there are still more gaps in test coverage 
to fill, with each patch being posted when ready, and review and 
discussion of patches can show up other things that need coverage as well 
(e.g. the extra coverage of strtod not changing errno when it's not meant 
to arising from discussion of the patch adding coverage for errno setting 
on overflow).  That's not very suited to posting or reviewing together at 
present.
  
Carlos O'Donell Aug. 19, 2024, 3:27 p.m. UTC | #3
On 8/19/24 11:00 AM, Joseph Myers wrote:
> On Mon, 19 Aug 2024, Carlos O'Donell wrote:
> 
>> On 8/16/24 6:25 PM, Joseph Myers wrote:
>>> This patch is relative to a tree with
>>> <https://sourceware.org/pipermail/libc-alpha/2024-August/159229.html>
>>> (pending review) applied.  There is no logical dependency on that
>>> patch; it's simply that both of them involve regenerating
>>> tst-strtod-round-data.h.
>>
>> While there is no logical dependency, as a reviewer I want to try apply 
>> all of your patches and review and test together to make my review more 
>> meaningful.
>>
>> Would it be possible for you to post these together as a "loose" series 
>> that collects everything for pre-commit CI to test and a reviewer to 
>> apply?
> 
> The "series" is ongoing in that there are still more gaps in test coverage 
> to fill, with each patch being posted when ready, and review and 
> discussion of patches can show up other things that need coverage as well 
> (e.g. the extra coverage of strtod not changing errno when it's not meant 
> to arising from discussion of the patch adding coverage for errno setting 
> on overflow).  That's not very suited to posting or reviewing together at 
> present.

I agree with your position, and it would be nice to have dependencies expressed for patches
in patchwork e.g. "Depends on Message-Id: <>" in order for a tester to be able to walk the
patches backwards, such support doesn't exist today.

How do we make it easier for a reviewer to get and test the entire loose collection?

Can we write some script that uses dependency information encoded in the commit message?

It looks like we could use b4 0.14+ features for this?
https://b4.docs.kernel.org/en/latest/contributor/prep.html#working-with-series-dependencies
  
Joseph Myers Aug. 22, 2024, 11:42 a.m. UTC | #4
Ping.  This patch 
<https://sourceware.org/pipermail/libc-alpha/2024-August/159262.html> is 
pending review.
  
Adhemerval Zanella Netto Aug. 26, 2024, 7:40 p.m. UTC | #5
On 16/08/24 19:25, Joseph Myers wrote:
> As reported in bug 30220, the implementation of strtod-family
> functions has a bug in the following case: the input string would,
> with infinite exponent range, take one more bit to represent than is
> available in the normal precision of the return type; the value
> represented is in the subnormal range; and there are no nonzero bits
> in the value, below those that can be represented in subnormal
> precision, other than the least significant bit and possibly the
> 0.5ulp bit.  In this case, round_and_return ends up discarding the
> least significant bit.
> 
> Fix by saving that bit to merge into more_bits (it can't be merged in
> at the time it's computed, because more_bits mustn't include this bit
> in the case of after-rounding tininess detection checking if the
> result is still subnormal when rounded to normal precision, so merging
> this bit into more_bits needs to take place after that check).
> 
> Tested for x86_64.

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> 
> ---
> 
> This patch is relative to a tree with
> <https://sourceware.org/pipermail/libc-alpha/2024-August/159229.html>
> (pending review) applied.  There is no logical dependency on that
> patch; it's simply that both of them involve regenerating
> tst-strtod-round-data.h.
> 
> diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
> index be515ce659..beb97b3d0c 100644
> --- a/stdlib/strtod_l.c
> +++ b/stdlib/strtod_l.c
> @@ -222,6 +222,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
>  
>        mp_size_t shift = MIN_EXP - 1 - exponent;
>        bool is_tiny = true;
> +      bool old_half_bit = (round_limb & (((mp_limb_t) 1) << round_bit)) != 0;
>  
>        more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
>        if (shift == MANT_DIG)
> @@ -292,6 +293,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
>  	  round_bit = shift - 1;
>  	  (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
>  	}
> +      more_bits |= old_half_bit;
>        /* This is a hook for the m68k long double format, where the
>  	 exponent bias is the same for normalized and denormalized
>  	 numbers.  */
> diff --git a/stdlib/tst-strtod-round-data b/stdlib/tst-strtod-round-data
> index 84ab705709..9489fbcc9c 100644
> --- a/stdlib/tst-strtod-round-data
> +++ b/stdlib/tst-strtod-round-data
> @@ -265,3 +265,15 @@
>  1.000000000000000000000000000000000385185988877447170611195588516985463707620329643077639047987759113311767578125
>  1.0000000000000000000000000000000001925929944387235853055977942584927318538101648215388195239938795566558837890625
>  1.00000000000000000000000000000000009629649721936179265279889712924636592690508241076940976199693977832794189453125
> +0x30000002222225p-1077
> +0x0.7fffffffffffeap-1022
> +0x0.7fffffffffffe9p-1022
> +0x0.7ffffd4p-126
> +0x0.7ffffffffffffffd4p-16382
> +0x0.7ffffffffffffffd4p-16383
> +0x0.7ffffffffffffffffffffffffffeap-16382
> +0x0.7000004p-126
> +0x0.70000000000002p-1022
> +0x0.70000000000000004p-16382
> +0x0.70000000000000004p-16383
> +0x0.70000000000000000000000000002p-16382
> diff --git a/stdlib/tst-strtod-round-data.h b/stdlib/tst-strtod-round-data.h
> index 13e62dd2b0..ed50eb2537 100644
> --- a/stdlib/tst-strtod-round-data.h
> +++ b/stdlib/tst-strtod-round-data.h
> @@ -15437,4 +15437,376 @@ static const struct test tests[] = {
>  	0x1p+0, false, false,
>  	0x1p+0, false, false,
>  	0x1.0000000000000000000000000001p+0, false, false),
> +  TEST ("0x30000002222225p-1077",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x1.800000111111p-1024, false, true,
> +	0x1.8000001111114p-1024, false, true,
> +	0x1.800000111111p-1024, false, true,
> +	0x1.8000001111114p-1024, false, true,
> +	true,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	true,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	false,
> +	0x1.800000111111p-1024, false, true,
> +	0x1.8000001111114p-1024, false, true,
> +	0x1.800000111111p-1024, false, true,
> +	0x1.8000001111114p-1024, false, true,
> +	true,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false,
> +	0x1.80000011111128p-1024, false, false),
> +  TEST ("0x0.7fffffffffffeap-1022",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	true,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	true,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	false,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	true,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false,
> +	0x1.ffffffffffffa8p-1024, false, false),
> +  TEST ("0x0.7fffffffffffe9p-1022",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	true,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	true,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	false,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	0x1.ffffffffffff8p-1024, false, true,
> +	0x1.ffffffffffffcp-1024, false, true,
> +	true,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false,
> +	0x1.ffffffffffffa4p-1024, false, false),
> +  TEST ("0x0.7ffffd4p-126",
> +	false,
> +	0x1.fffffp-128, false, true,
> +	0x1.fffff8p-128, false, true,
> +	0x1.fffffp-128, false, true,
> +	0x1.fffff8p-128, false, true,
> +	true,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	true,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	true,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	true,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	true,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false,
> +	0x1.fffff5p-128, false, false),
> +  TEST ("0x0.7ffffffffffffffd4p-16382",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0x1.fffffffffffffffp-16384, false, true,
> +	0x1.fffffffffffffff8p-16384, false, true,
> +	0x1.fffffffffffffffp-16384, false, true,
> +	0x1.fffffffffffffff8p-16384, false, true,
> +	false,
> +	0x1.fffffffffffffff4p-16384, false, true,
> +	0x1.fffffffffffffff4p-16384, false, true,
> +	0x1.fffffffffffffff4p-16384, false, true,
> +	0x1.fffffffffffffff8p-16384, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	true,
> +	0x1.fffffffffffffff5p-16384, false, false,
> +	0x1.fffffffffffffff5p-16384, false, false,
> +	0x1.fffffffffffffff5p-16384, false, false,
> +	0x1.fffffffffffffff5p-16384, false, false),
> +  TEST ("0x0.7ffffffffffffffd4p-16383",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0xf.ffffffffffffff8p-16388, false, true,
> +	0xf.ffffffffffffff8p-16388, false, true,
> +	0xf.ffffffffffffff8p-16388, false, true,
> +	0x1p-16384, false, true,
> +	false,
> +	0xf.ffffffffffffff8p-16388, false, true,
> +	0xf.ffffffffffffffcp-16388, false, true,
> +	0xf.ffffffffffffff8p-16388, false, true,
> +	0xf.ffffffffffffffcp-16388, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	true,
> +	0xf.ffffffffffffffa8p-16388, false, false,
> +	0xf.ffffffffffffffa8p-16388, false, false,
> +	0xf.ffffffffffffffa8p-16388, false, false,
> +	0xf.ffffffffffffffa8p-16388, false, false),
> +  TEST ("0x0.7ffffffffffffffffffffffffffeap-16382",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0x1.fffffffffffffff8p-16384, false, true,
> +	0x2p-16384, false, true,
> +	0x1.fffffffffffffff8p-16384, false, true,
> +	0x2p-16384, false, true,
> +	false,
> +	0x1.fffffffffffffffcp-16384, false, true,
> +	0x2p-16384, false, true,
> +	0x1.fffffffffffffffcp-16384, false, true,
> +	0x2p-16384, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0x1.fffffffffffffffffffffffffff8p-16384, false, true,
> +	0x1.fffffffffffffffffffffffffffcp-16384, false, true,
> +	0x1.fffffffffffffffffffffffffff8p-16384, false, true,
> +	0x1.fffffffffffffffffffffffffffcp-16384, false, true),
> +  TEST ("0x0.7000004p-126",
> +	false,
> +	0x1.cp-128, false, true,
> +	0x1.cp-128, false, true,
> +	0x1.cp-128, false, true,
> +	0x1.c00008p-128, false, true,
> +	true,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	true,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	true,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	true,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	true,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false,
> +	0x1.c00001p-128, false, false),
> +  TEST ("0x0.70000000000002p-1022",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x1.cp-1024, false, true,
> +	0x1.cp-1024, false, true,
> +	0x1.cp-1024, false, true,
> +	0x1.c000000000004p-1024, false, true,
> +	true,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	true,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	false,
> +	0x1.cp-1024, false, true,
> +	0x1.cp-1024, false, true,
> +	0x1.cp-1024, false, true,
> +	0x1.c000000000004p-1024, false, true,
> +	true,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false,
> +	0x1.c0000000000008p-1024, false, false),
> +  TEST ("0x0.70000000000000004p-16382",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.c000000000000008p-16384, false, true,
> +	false,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.c000000000000004p-16384, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	true,
> +	0x1.c000000000000001p-16384, false, false,
> +	0x1.c000000000000001p-16384, false, false,
> +	0x1.c000000000000001p-16384, false, false,
> +	0x1.c000000000000001p-16384, false, false),
> +  TEST ("0x0.70000000000000004p-16383",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0xep-16388, false, true,
> +	0xep-16388, false, true,
> +	0xep-16388, false, true,
> +	0xe.000000000000008p-16388, false, true,
> +	false,
> +	0xep-16388, false, true,
> +	0xep-16388, false, true,
> +	0xep-16388, false, true,
> +	0xe.000000000000004p-16388, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	true,
> +	0xe.0000000000000008p-16388, false, false,
> +	0xe.0000000000000008p-16388, false, false,
> +	0xe.0000000000000008p-16388, false, false,
> +	0xe.0000000000000008p-16388, false, false),
> +  TEST ("0x0.70000000000000000000000000002p-16382",
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x8p-152, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.c000000000000008p-16384, false, true,
> +	false,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.c000000000000004p-16384, false, true,
> +	false,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x0p+0, false, true,
> +	0x4p-1076, false, true,
> +	false,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.cp-16384, false, true,
> +	0x1.c000000000000000000000000004p-16384, false, true),
>  };
>
  

Patch

diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c
index be515ce659..beb97b3d0c 100644
--- a/stdlib/strtod_l.c
+++ b/stdlib/strtod_l.c
@@ -222,6 +222,7 @@  round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
 
       mp_size_t shift = MIN_EXP - 1 - exponent;
       bool is_tiny = true;
+      bool old_half_bit = (round_limb & (((mp_limb_t) 1) << round_bit)) != 0;
 
       more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
       if (shift == MANT_DIG)
@@ -292,6 +293,7 @@  round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
 	  round_bit = shift - 1;
 	  (void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
 	}
+      more_bits |= old_half_bit;
       /* This is a hook for the m68k long double format, where the
 	 exponent bias is the same for normalized and denormalized
 	 numbers.  */
diff --git a/stdlib/tst-strtod-round-data b/stdlib/tst-strtod-round-data
index 84ab705709..9489fbcc9c 100644
--- a/stdlib/tst-strtod-round-data
+++ b/stdlib/tst-strtod-round-data
@@ -265,3 +265,15 @@ 
 1.000000000000000000000000000000000385185988877447170611195588516985463707620329643077639047987759113311767578125
 1.0000000000000000000000000000000001925929944387235853055977942584927318538101648215388195239938795566558837890625
 1.00000000000000000000000000000000009629649721936179265279889712924636592690508241076940976199693977832794189453125
+0x30000002222225p-1077
+0x0.7fffffffffffeap-1022
+0x0.7fffffffffffe9p-1022
+0x0.7ffffd4p-126
+0x0.7ffffffffffffffd4p-16382
+0x0.7ffffffffffffffd4p-16383
+0x0.7ffffffffffffffffffffffffffeap-16382
+0x0.7000004p-126
+0x0.70000000000002p-1022
+0x0.70000000000000004p-16382
+0x0.70000000000000004p-16383
+0x0.70000000000000000000000000002p-16382
diff --git a/stdlib/tst-strtod-round-data.h b/stdlib/tst-strtod-round-data.h
index 13e62dd2b0..ed50eb2537 100644
--- a/stdlib/tst-strtod-round-data.h
+++ b/stdlib/tst-strtod-round-data.h
@@ -15437,4 +15437,376 @@  static const struct test tests[] = {
 	0x1p+0, false, false,
 	0x1p+0, false, false,
 	0x1.0000000000000000000000000001p+0, false, false),
+  TEST ("0x30000002222225p-1077",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x1.800000111111p-1024, false, true,
+	0x1.8000001111114p-1024, false, true,
+	0x1.800000111111p-1024, false, true,
+	0x1.8000001111114p-1024, false, true,
+	true,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	true,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	false,
+	0x1.800000111111p-1024, false, true,
+	0x1.8000001111114p-1024, false, true,
+	0x1.800000111111p-1024, false, true,
+	0x1.8000001111114p-1024, false, true,
+	true,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false,
+	0x1.80000011111128p-1024, false, false),
+  TEST ("0x0.7fffffffffffeap-1022",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	true,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	true,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	false,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	true,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false,
+	0x1.ffffffffffffa8p-1024, false, false),
+  TEST ("0x0.7fffffffffffe9p-1022",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	true,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	true,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	false,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	0x1.ffffffffffff8p-1024, false, true,
+	0x1.ffffffffffffcp-1024, false, true,
+	true,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false,
+	0x1.ffffffffffffa4p-1024, false, false),
+  TEST ("0x0.7ffffd4p-126",
+	false,
+	0x1.fffffp-128, false, true,
+	0x1.fffff8p-128, false, true,
+	0x1.fffffp-128, false, true,
+	0x1.fffff8p-128, false, true,
+	true,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	true,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	true,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	true,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	true,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false,
+	0x1.fffff5p-128, false, false),
+  TEST ("0x0.7ffffffffffffffd4p-16382",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0x1.fffffffffffffffp-16384, false, true,
+	0x1.fffffffffffffff8p-16384, false, true,
+	0x1.fffffffffffffffp-16384, false, true,
+	0x1.fffffffffffffff8p-16384, false, true,
+	false,
+	0x1.fffffffffffffff4p-16384, false, true,
+	0x1.fffffffffffffff4p-16384, false, true,
+	0x1.fffffffffffffff4p-16384, false, true,
+	0x1.fffffffffffffff8p-16384, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	true,
+	0x1.fffffffffffffff5p-16384, false, false,
+	0x1.fffffffffffffff5p-16384, false, false,
+	0x1.fffffffffffffff5p-16384, false, false,
+	0x1.fffffffffffffff5p-16384, false, false),
+  TEST ("0x0.7ffffffffffffffd4p-16383",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0xf.ffffffffffffff8p-16388, false, true,
+	0xf.ffffffffffffff8p-16388, false, true,
+	0xf.ffffffffffffff8p-16388, false, true,
+	0x1p-16384, false, true,
+	false,
+	0xf.ffffffffffffff8p-16388, false, true,
+	0xf.ffffffffffffffcp-16388, false, true,
+	0xf.ffffffffffffff8p-16388, false, true,
+	0xf.ffffffffffffffcp-16388, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	true,
+	0xf.ffffffffffffffa8p-16388, false, false,
+	0xf.ffffffffffffffa8p-16388, false, false,
+	0xf.ffffffffffffffa8p-16388, false, false,
+	0xf.ffffffffffffffa8p-16388, false, false),
+  TEST ("0x0.7ffffffffffffffffffffffffffeap-16382",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0x1.fffffffffffffff8p-16384, false, true,
+	0x2p-16384, false, true,
+	0x1.fffffffffffffff8p-16384, false, true,
+	0x2p-16384, false, true,
+	false,
+	0x1.fffffffffffffffcp-16384, false, true,
+	0x2p-16384, false, true,
+	0x1.fffffffffffffffcp-16384, false, true,
+	0x2p-16384, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0x1.fffffffffffffffffffffffffff8p-16384, false, true,
+	0x1.fffffffffffffffffffffffffffcp-16384, false, true,
+	0x1.fffffffffffffffffffffffffff8p-16384, false, true,
+	0x1.fffffffffffffffffffffffffffcp-16384, false, true),
+  TEST ("0x0.7000004p-126",
+	false,
+	0x1.cp-128, false, true,
+	0x1.cp-128, false, true,
+	0x1.cp-128, false, true,
+	0x1.c00008p-128, false, true,
+	true,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	true,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	true,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	true,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	true,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false,
+	0x1.c00001p-128, false, false),
+  TEST ("0x0.70000000000002p-1022",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x1.cp-1024, false, true,
+	0x1.cp-1024, false, true,
+	0x1.cp-1024, false, true,
+	0x1.c000000000004p-1024, false, true,
+	true,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	true,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	false,
+	0x1.cp-1024, false, true,
+	0x1.cp-1024, false, true,
+	0x1.cp-1024, false, true,
+	0x1.c000000000004p-1024, false, true,
+	true,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false,
+	0x1.c0000000000008p-1024, false, false),
+  TEST ("0x0.70000000000000004p-16382",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.c000000000000008p-16384, false, true,
+	false,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.c000000000000004p-16384, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	true,
+	0x1.c000000000000001p-16384, false, false,
+	0x1.c000000000000001p-16384, false, false,
+	0x1.c000000000000001p-16384, false, false,
+	0x1.c000000000000001p-16384, false, false),
+  TEST ("0x0.70000000000000004p-16383",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0xep-16388, false, true,
+	0xep-16388, false, true,
+	0xep-16388, false, true,
+	0xe.000000000000008p-16388, false, true,
+	false,
+	0xep-16388, false, true,
+	0xep-16388, false, true,
+	0xep-16388, false, true,
+	0xe.000000000000004p-16388, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	true,
+	0xe.0000000000000008p-16388, false, false,
+	0xe.0000000000000008p-16388, false, false,
+	0xe.0000000000000008p-16388, false, false,
+	0xe.0000000000000008p-16388, false, false),
+  TEST ("0x0.70000000000000000000000000002p-16382",
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x8p-152, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.c000000000000008p-16384, false, true,
+	false,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.c000000000000004p-16384, false, true,
+	false,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x0p+0, false, true,
+	0x4p-1076, false, true,
+	false,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.cp-16384, false, true,
+	0x1.c000000000000000000000000004p-16384, false, true),
 };