Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20260521131529.GT1827@brightrain.aerifal.cx>
Date: Thu, 21 May 2026 09:15:30 -0400
From: Rich Felker <dalias@...c.org>
To: Sertonix <sertonix@...teo.net>
Cc: musl@...ts.openwall.com
Subject: Re: strtod:

On Thu, May 21, 2026 at 08:56:41AM +0000, Sertonix wrote:
> On Thu May 21, 2026 at 4:55 AM CEST, Rich Felker wrote:
> > On Wed, May 20, 2026 at 10:22:18PM -0400, Rich Felker wrote:
> >> On Thu, May 21, 2026 at 01:33:13AM +0000, Sertonix wrote:
> >> > Hi,
> >> > 
> >> > I noticed a subtle difference in the result of strtod on alpine linux
> >> > between arm/ppc64le and other arches. The following reproducer shows
> >> > 1.3754889325393114e+24 on x86_64 and 1.3754889325393111e+24 on armv7.
> >> > Is this maybe a musl bug or is that level of precision undefined?
> >> > 
> >> > #include <stdio.h>
> >> > #include <stdlib.h>
> >> > 
> >> > int main() {
> >> > 	char *end;
> >> > 	double v = strtod("0x0123456789ABCDEFabcdef", &end);
> >> > 	printf("%.16e\n", v);
> >> > }
> >> 
> >> I confirmed this report. It seems to give the wrong output (rounding
> >> down instead of up) on all archs with 64-bit long double (same as
> >> double). I'll have to step thru the execution and see where it's going
> >> wrong. I'll see if I can figure it out tomorrow if nobody beats me to
> >> it.
> >> 
> >> BTW the issue is easier to see if you change the %.16e to %a.
> >
> > I think this fixes it.
> 
> 
> Thanks! With the patch applied the binaryen test suite no longer fails
> on these arches.

Great!

The problem seems to have been that we rounded down computing the
number of hex digits needed in order for additional digits not to be
significant except for whether a nonzero digit appears. This was fine
for ld80 since 64 is an exact multiple of 4, but not for ld64 (53
isn't a multiple of 4) and also not for ld128 (113 is not a multiple
of 4). I'll see if I can produce a testcase that gets the wrong result
on ld128 to document that it was broken too.

..and before I remembered to hit send, I've got one:

input:  0x1.11111111111111111111111111111p0
expect: 0x1.1111111111111111111111111111p+0
result: 0x1.1111111111111111111111111112p+0

This is because only the first 28 digits are consumed, and the 29th
being nonzero is just treated as "nonzero tail", causing a final 0.5
to be added which triggers rounding up to even in the default rounding
mode.

With the same fix as in this patch, the final 1 is consumed, which
correctly gets rounded down in default rounding mode. If there were
more digits, the 0.5 would be further out, and would not affect the
rounding except when it's supposed to (when the part to be truncated
is exactly halfway).

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.