NetBSD Problem Report #57250
From martin@aprisoft.de Tue Feb 28 15:01:40 2023
Return-Path: <martin@aprisoft.de>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 9BB381A9239
for <gnats-bugs@gnats.NetBSD.org>; Tue, 28 Feb 2023 15:01:40 +0000 (UTC)
Message-Id: <20230228150130.983945CC81D@emmas.aprisoft.de>
Date: Tue, 28 Feb 2023 16:01:30 +0100 (CET)
From: martin@NetBSD.org
Reply-To: martin@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: dtoa mishandles infinite doubles on 32bit big endian machines
X-Send-Pr-Version: 3.95
>Number: 57250
>Category: lib
>Synopsis: dtoa mishandles infinite doubles on 32bit big endian machines
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: lib-bug-people
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Feb 28 15:05:00 +0000 2023
>Closed-Date: Thu Apr 06 14:52:52 +0000 2023
>Last-Modified: Mon Apr 17 18:25:02 +0000 2023
>Originator: Martin Husemann
>Release: NetBSD 10.99.2
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD big-apple.aprisoft.de 10.99.2 NetBSD 10.99.2 (POWERMAC_G5.MP) #95: Tue Feb 14 11:59:21 CET 2023 martin@seven-days-to-the-wolves.aprisoft.de:/work/src/sys/arch/macppc/compile/POWERMAC_G5.MP macppc
Architecture: powerpc
Machine: macppc
>Description:
While looking at a lint test failure on some machines Roland came up with
this test code:
---8<---
#include <err.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static void
lex_floating_constant(const char *cp)
{
errno = 0;
char *eptr;
long double ld = strtold(cp, &eptr);
if (errno != 0)
warn("errno");
ld = (double)ld;
if (isfinite(ld) == 0)
warnx("infinite");
printf("%Lf\n", ld);
}
int
main(int argc, char **argv)
{
lex_floating_constant(argv[1]);
}
--->8---
compiling and invoking it with 1e309 shows strange output on 32bit big
endian machines:
test: errno: Result too large or too small
test: infinite
Infinity0000000000000000000000000000000000000000000000000000000[...]
while the expected output is:
[/tmp] martin@thirdstage > ./test 1e309
test: infinite
inf
[/tmp] martin@thirdstage >
The failure happens at least on sparc, powerpc and evbearmv7hf-eb.
It works on 64bit big endian (sparc64) and all little endian machines I
tested.
>How-To-Repeat:
s/a
>Fix:
n/a
>Release-Note:
>Audit-Trail:
From: David Holland <dholland-bugs@netbsd.org>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: lib/57250: dtoa mishandles infinite doubles on 32bit big endian
machines
Date: Sun, 2 Apr 2023 00:35:34 +0000
On Tue, Feb 28, 2023 at 03:05:00PM +0000, martin@NetBSD.org wrote:
> compiling and invoking it with 1e309 shows strange output on 32bit big
> endian machines:
>
> test: errno: Result too large or too small
> test: infinite
> Infinity0000000000000000000000000000000000000000000000000000000[...]
>
> while the expected output is:
>
> [/tmp] martin@thirdstage > ./test 1e309
> test: infinite
> inf
> [/tmp] martin@thirdstage >
>
> The failure happens at least on sparc, powerpc and evbearmv7hf-eb.
> It works on 64bit big endian (sparc64) and all little endian machines I
> tested.
Tracing through all the baling wire, it seems that there are two
different copies of the printf logic. One begins at line 1062 of
vfwprintf.c; in this one we get "inf" if calling __ldtoa returns
INT_MAX in expt and a string that doesn't begin with 'N'. The other
begins at line 1174, and in that one we get "inf" if isinf() returns
true.
They're selected based on #ifdef WIDE_DOUBLE, which seems from the
logic to be meant to be set if long double is different from double.
Checking which copy of the code is in use is probably a good idea; I
don't have any of the effected machines to try.
It appears that the non-WIDE_DOUBLE code is lacking support for %a and
%A, so printing with that is a quick way to check.
With WIDE_DOUBLE the ldtoa code (ldtoa.c and gdtoa.c) seems to only be
able to produce the string "Infinity" on its own, and tracing through
all the magic number signalling that leads to producing INT_MAX it
_looks_ correct, so getting a string of zeros after it suggests some
other path.
The most plausible hypothesis at the moment seems to be that the
failing platforms are not using WIDE_DOUBLE and also isinf() is
broken, so they go through the logic at line 1259 using the magic
exponent return of 9999 and print a ton of zeros at line 1520. How
many zeros are you getting?
--
David A. Holland
dholland@netbsd.org
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: lib/57250: dtoa mishandles infinite doubles on 32bit big endian
machines
Date: Sun, 2 Apr 2023 11:29:21 +0200
We seem to set WIDE_DOUBLE unconditionally in stdio/Makefile.inc.
All of the affected platforms (that I know about) have
sizeof(double) == sizeof(long double) == 8.
Martin
From: Havard Eidnes <he@NetBSD.org>
To: gnats-bugs@netbsd.org, martin@duskware.de
Cc: lib-bug-people@netbsd.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, martin@NetBSD.org
Subject: Re: lib/57250: dtoa mishandles infinite doubles on 32bit big
endian machines
Date: Mon, 03 Apr 2023 15:01:19 +0200 (CEST)
Hi,
based on hints from Martin, and a suggestion that the non-
WIDE_DOUBLE code misses handling for %a and %A, I came up with
this diff which at least produces one correct result for %a on
NetBSD/macppc :)
"More testing required".
Regards,
- Havard
------------------------------
Index: include/extern.h
===================================================================
RCS file: /cvsroot/src/lib/libc/include/extern.h,v
retrieving revision 1.26
diff -u -p -r1.26 extern.h
--- include/extern.h 15 May 2020 14:37:21 -0000 1.26
+++ include/extern.h 3 Apr 2023 12:33:57 -0000
@@ -49,11 +49,17 @@ struct sigaction;
int __sigaction_sigtramp(int, const struct sigaction *,
struct sigaction *, const void *, int);
+/* is "long double" and "double" different? */
+#if (__LDBL_MANT_DIG__ != __DBL_MANT_DIG__) || \
+ (__LDBL_MAX_EXP__ != __DBL_MAX_EXP__)
+#define WIDE_DOUBLE
+#endif
+
#ifdef WIDE_DOUBLE
-char *__hdtoa(double, const char *, int, int *, int *, char **);
char *__hldtoa(long double, const char *, int, int *, int *, char **);
char *__ldtoa(long double *, int, int, int *, int *, char **);
#endif
+char *__hdtoa(double, const char *, int, int *, int *, char **);
#ifndef __LIBC12_SOURCE__
struct syslog_data;
Index: stdio/Makefile.inc
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/Makefile.inc,v
retrieving revision 1.47
diff -u -p -r1.47 Makefile.inc
--- stdio/Makefile.inc 29 Dec 2015 17:55:23 -0000 1.47
+++ stdio/Makefile.inc 3 Apr 2023 12:33:57 -0000
@@ -4,8 +4,6 @@
# stdio sources
.PATH: ${.CURDIR}/stdio
-CPPFLAGS+=-DWIDE_DOUBLE
-
SRCS+= clrerr.c dprintf.c fclose.c fdopen.c feof.c ferror.c \
fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetstr.c fgetwc.c \
fgetwln.c fgetws.c fileno.c findfp.c flags.c flockfile.c fopen.c \
Index: stdio/vfwprintf.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/vfwprintf.c,v
retrieving revision 1.39
diff -u -p -r1.39 vfwprintf.c
--- stdio/vfwprintf.c 19 Apr 2022 20:32:16 -0000 1.39
+++ stdio/vfwprintf.c 3 Apr 2023 12:33:57 -0000
@@ -650,16 +650,16 @@ WDECL(__vf,printf_unlocked_l)(FILE *fp,
*/
char *decimal_point; /* locale specific decimal point */
#ifdef WIDE_DOUBLE
- int signflag; /* true if float is negative */
union { /* floating point arguments %[aAeEfFgG] */
double dbl;
long double ldbl;
} fparg;
- char *dtoaend; /* pointer to end of converted digits */
#else
double _double; /* double precision arguments %[eEfgG] */
char softsign; /* temporary negative sign for floats */
#endif
+ int signflag; /* true if float is negative */
+ char *dtoaend; /* pointer to end of converted digits */
char *dtoaresult; /* buffer allocated by dtoa */
int expt; /* integer value of exponent */
char expchar; /* exponent character: [eEpP\0] */
@@ -1170,7 +1170,64 @@ fp_common:
flags &= ~ZEROPAD;
break;
}
+#else /* ! WIDE_DOUBLE */
+ case 'a':
+ case 'A':
+ if (ch == 'a') {
+ ox[1] = 'x';
+ xdigs = xdigs_lower;
+ expchar = 'p';
+ } else {
+ ox[1] = 'X';
+ xdigs = xdigs_upper;
+ expchar = 'P';
+ }
+ if (prec >= 0)
+ prec++;
+
+ _double = GETARG(double);
+ dtoaresult =
+ __hdtoa(_double, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+ if (dtoaresult == NULL)
+ goto oomem;
+
+ if (prec < 0) {
+ _DIAGASSERT(__type_fit(int,
+ dtoaend - dtoaresult));
+ prec = (int)(dtoaend - dtoaresult);
+ }
+ if (expt == INT_MAX)
+ ox[1] = '\0';
+ _DIAGASSERT(__type_fit(int, dtoaend - dtoaresult));
+ ndig = (int)(dtoaend - dtoaresult);
+ if (convbuf != NULL)
+ free(convbuf);
+#ifndef NARROW
+ result = convbuf = __mbsconv(dtoaresult, -1, loc);
#else
+ /*XXX inefficient*/
+ result = convbuf = strdup(dtoaresult);
+#endif
+ if (result == NULL)
+ goto oomem;
+ __freedtoa(dtoaresult);
+
+ if (signflag)
+ sign = '-';
+ if (expt == INT_MAX) { /* inf or nan */
+ if (*result == 'N') {
+ result = (ch >= 'a') ? STRCONST("nan") :
+ STRCONST("NAN");
+ sign = '\0';
+ } else
+ result = (ch >= 'a') ? STRCONST("inf") :
+ STRCONST("INF");
+ size = 3;
+ flags &= ~ZEROPAD;
+ break;
+ }
+ goto fp_common_wrapup;
case 'e':
case 'E':
case 'f':
@@ -1229,7 +1286,8 @@ fp_common:
__freedtoa(dtoaresult);
if (softsign)
sign = '-';
-#endif
+#endif /* WIDE_DOUBLE */
+ fp_common_wrapup:
flags |= FPT;
if (ch == 'g' || ch == 'G') {
if (expt > -4 && expt <= prec) {
From: Havard Eidnes <he@NetBSD.org>
To: gnats-bugs@netbsd.org, martin@duskware.de
Cc: lib-bug-people@netbsd.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, martin@NetBSD.org
Subject: Re: lib/57250: dtoa mishandles infinite doubles on 32bit big
endian machines
Date: Tue, 04 Apr 2023 20:24:13 +0200 (CEST)
Hi,
a slightly simpler diff with less code duplication.
- Havard
------------------------------
Index: include/extern.h
===================================================================
RCS file: /cvsroot/src/lib/libc/include/extern.h,v
retrieving revision 1.26
diff -u -p -r1.26 extern.h
--- include/extern.h 15 May 2020 14:37:21 -0000 1.26
+++ include/extern.h 4 Apr 2023 18:21:25 -0000
@@ -49,11 +49,17 @@ struct sigaction;
int __sigaction_sigtramp(int, const struct sigaction *,
struct sigaction *, const void *, int);
+/* is "long double" and "double" different? */
+#if (__LDBL_MANT_DIG__ != __DBL_MANT_DIG__) || \
+ (__LDBL_MAX_EXP__ != __DBL_MAX_EXP__)
+#define WIDE_DOUBLE
+#endif
+
#ifdef WIDE_DOUBLE
-char *__hdtoa(double, const char *, int, int *, int *, char **);
char *__hldtoa(long double, const char *, int, int *, int *, char **);
char *__ldtoa(long double *, int, int, int *, int *, char **);
#endif
+char *__hdtoa(double, const char *, int, int *, int *, char **);
#ifndef __LIBC12_SOURCE__
struct syslog_data;
Index: stdio/Makefile.inc
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/Makefile.inc,v
retrieving revision 1.47
diff -u -p -r1.47 Makefile.inc
--- stdio/Makefile.inc 29 Dec 2015 17:55:23 -0000 1.47
+++ stdio/Makefile.inc 4 Apr 2023 18:21:25 -0000
@@ -4,8 +4,6 @@
# stdio sources
.PATH: ${.CURDIR}/stdio
-CPPFLAGS+=-DWIDE_DOUBLE
-
SRCS+= clrerr.c dprintf.c fclose.c fdopen.c feof.c ferror.c \
fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetstr.c fgetwc.c \
fgetwln.c fgetws.c fileno.c findfp.c flags.c flockfile.c fopen.c \
Index: stdio/vfwprintf.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/vfwprintf.c,v
retrieving revision 1.39
diff -u -p -r1.39 vfwprintf.c
--- stdio/vfwprintf.c 19 Apr 2022 20:32:16 -0000 1.39
+++ stdio/vfwprintf.c 4 Apr 2023 18:21:25 -0000
@@ -650,16 +650,16 @@ WDECL(__vf,printf_unlocked_l)(FILE *fp,
*/
char *decimal_point; /* locale specific decimal point */
#ifdef WIDE_DOUBLE
- int signflag; /* true if float is negative */
union { /* floating point arguments %[aAeEfFgG] */
double dbl;
long double ldbl;
} fparg;
- char *dtoaend; /* pointer to end of converted digits */
#else
double _double; /* double precision arguments %[eEfgG] */
- char softsign; /* temporary negative sign for floats */
+ char softsign = 0; /* temporary negative sign for floats */
#endif
+ int signflag = 0; /* true if float is negative */
+ char *dtoaend; /* pointer to end of converted digits */
char *dtoaresult; /* buffer allocated by dtoa */
int expt; /* integer value of exponent */
char expchar; /* exponent character: [eEpP\0] */
@@ -1058,7 +1058,6 @@ reswitch: switch (ch) {
base = 10;
goto number;
#ifndef NO_FLOATING_POINT
-#ifdef WIDE_DOUBLE
case 'a':
case 'A':
if (ch == 'a') {
@@ -1072,6 +1071,7 @@ reswitch: switch (ch) {
}
if (prec >= 0)
prec++;
+#ifdef WIDE_DOUBLE
if (flags & LONGDBL) {
fparg.ldbl = GETARG(long double);
dtoaresult =
@@ -1083,6 +1083,12 @@ reswitch: switch (ch) {
__hdtoa(fparg.dbl, xdigs, prec,
&expt, &signflag, &dtoaend);
}
+#else /* !WIDE_DOUBLE */
+ _double = GETARG(double);
+ dtoaresult =
+ __hdtoa(_double, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+#endif /* WIDE_DOUBLE */
if (dtoaresult == NULL)
goto oomem;
@@ -1107,6 +1113,8 @@ reswitch: switch (ch) {
goto oomem;
__freedtoa(dtoaresult);
goto fp_common;
+#ifdef WIDE_DOUBLE
+
case 'e':
case 'E':
expchar = ch;
@@ -1170,7 +1178,7 @@ fp_common:
flags &= ~ZEROPAD;
break;
}
-#else
+#else /* !WIDE_DOUBLE */
case 'e':
case 'E':
case 'f':
@@ -1227,9 +1235,11 @@ fp_common:
if (result == NULL)
goto oomem;
__freedtoa(dtoaresult);
- if (softsign)
+fp_common:
+ if (signflag || softsign)
sign = '-';
-#endif
+#endif /* WIDE_DOUBLE */
+
flags |= FPT;
if (ch == 'g' || ch == 'G') {
if (expt > -4 && expt <= prec) {
From: Havard Eidnes <he@NetBSD.org>
To: gnats-bugs@netbsd.org, martin@duskware.de
Cc: lib-bug-people@netbsd.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, martin@NetBSD.org
Subject: Re: lib/57250: dtoa mishandles infinite doubles on 32bit big
endian machines
Date: Tue, 04 Apr 2023 20:49:25 +0200 (CEST)
...and after Christos massaged the code to do more code sharing
(and delete some now-un-needed code), and fixing the
non-WIDE_DOUBLE build issues, this is the resulting diff.
- Havard
------------------------------
Index: include/extern.h
===================================================================
RCS file: /cvsroot/src/lib/libc/include/extern.h,v
retrieving revision 1.26
diff -u -p -r1.26 extern.h
--- include/extern.h 15 May 2020 14:37:21 -0000 1.26
+++ include/extern.h 4 Apr 2023 18:44:22 -0000
@@ -49,11 +49,17 @@ struct sigaction;
int __sigaction_sigtramp(int, const struct sigaction *,
struct sigaction *, const void *, int);
+/* is "long double" and "double" different? */
+#if (__LDBL_MANT_DIG__ != __DBL_MANT_DIG__) || \
+ (__LDBL_MAX_EXP__ != __DBL_MAX_EXP__)
+#define WIDE_DOUBLE
+#endif
+
#ifdef WIDE_DOUBLE
-char *__hdtoa(double, const char *, int, int *, int *, char **);
char *__hldtoa(long double, const char *, int, int *, int *, char **);
char *__ldtoa(long double *, int, int, int *, int *, char **);
#endif
+char *__hdtoa(double, const char *, int, int *, int *, char **);
#ifndef __LIBC12_SOURCE__
struct syslog_data;
Index: stdio/Makefile.inc
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/Makefile.inc,v
retrieving revision 1.47
diff -u -p -r1.47 Makefile.inc
--- stdio/Makefile.inc 29 Dec 2015 17:55:23 -0000 1.47
+++ stdio/Makefile.inc 4 Apr 2023 18:44:22 -0000
@@ -4,8 +4,6 @@
# stdio sources
.PATH: ${.CURDIR}/stdio
-CPPFLAGS+=-DWIDE_DOUBLE
-
SRCS+= clrerr.c dprintf.c fclose.c fdopen.c feof.c ferror.c \
fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetstr.c fgetwc.c \
fgetwln.c fgetws.c fileno.c findfp.c flags.c flockfile.c fopen.c \
Index: stdio/vfwprintf.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdio/vfwprintf.c,v
retrieving revision 1.39
diff -u -p -r1.39 vfwprintf.c
--- stdio/vfwprintf.c 19 Apr 2022 20:32:16 -0000 1.39
+++ stdio/vfwprintf.c 4 Apr 2023 18:44:22 -0000
@@ -581,9 +581,6 @@ WDECL(vf,printf_l)(FILE * __restrict fp,
#define DEFPREC 6
static int exponent(CHAR_T *, int, int);
-#ifndef WIDE_DOUBLE
-static char *cvt(double, int, int, char *, int *, int, int *);
-#endif
#endif /* !NO_FLOATING_POINT */
@@ -650,16 +647,15 @@ WDECL(__vf,printf_unlocked_l)(FILE *fp,
*/
char *decimal_point; /* locale specific decimal point */
#ifdef WIDE_DOUBLE
- int signflag; /* true if float is negative */
union { /* floating point arguments %[aAeEfFgG] */
double dbl;
long double ldbl;
} fparg;
- char *dtoaend; /* pointer to end of converted digits */
#else
double _double; /* double precision arguments %[eEfgG] */
- char softsign; /* temporary negative sign for floats */
#endif
+ int signflag; /* true if float is negative */
+ char *dtoaend; /* pointer to end of converted digits */
char *dtoaresult; /* buffer allocated by dtoa */
int expt; /* integer value of exponent */
char expchar; /* exponent character: [eEpP\0] */
@@ -1058,7 +1054,6 @@ reswitch: switch (ch) {
base = 10;
goto number;
#ifndef NO_FLOATING_POINT
-#ifdef WIDE_DOUBLE
case 'a':
case 'A':
if (ch == 'a') {
@@ -1072,6 +1067,7 @@ reswitch: switch (ch) {
}
if (prec >= 0)
prec++;
+#ifdef WIDE_DOUBLE
if (flags & LONGDBL) {
fparg.ldbl = GETARG(long double);
dtoaresult =
@@ -1083,6 +1079,12 @@ reswitch: switch (ch) {
__hdtoa(fparg.dbl, xdigs, prec,
&expt, &signflag, &dtoaend);
}
+#else
+ _double = GETARG(double);
+ dtoaresult =
+ __hdtoa(_double, xdigs, prec,
+ &expt, &signflag, &dtoaend);
+#endif /* WIDE_DOUBLE */
if (dtoaresult == NULL)
goto oomem;
@@ -1127,6 +1129,7 @@ reswitch: switch (ch) {
fp_begin:
if (prec < 0)
prec = DEFPREC;
+#ifdef WIDE_DOUBLE
if (flags & LONGDBL) {
fparg.ldbl = GETARG(long double);
dtoaresult =
@@ -1140,6 +1143,14 @@ fp_begin:
if (expt == 9999)
expt = INT_MAX;
}
+#else
+ _double = GETARG(double);
+ dtoaresult =
+ __dtoa(_double, expchar ? 2 : 3, prec,
+ &expt, &signflag, &dtoaend);
+ if (expt == 9999)
+ expt = INT_MAX;
+#endif /* WIDE_DOUBLE */
if (dtoaresult == NULL)
goto oomem;
_DIAGASSERT(__type_fit(int, dtoaend - dtoaresult));
@@ -1170,67 +1181,8 @@ fp_common:
flags &= ~ZEROPAD;
break;
}
-#else
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- if (prec == -1) {
- prec = DEFPREC;
- } else if ((ch == 'g' || ch == 'G') && prec == 0) {
- prec = 1;
- }
-
- if (flags & LONGDBL) {
- _double = (double) GETARG(long double);
- } else {
- _double = GETARG(double);
- }
-
- /* do this before tricky precision changes */
- if (isinf(_double)) {
- if (_double < 0)
- sign = '-';
- if (ch == 'E' || ch == 'F' || ch == 'G')
- result = STRCONST("INF");
- else
- result = STRCONST("inf");
- size = 3;
- flags &= ~ZEROPAD;
- break;
- }
- if (isnan(_double)) {
- if (ch == 'E' || ch == 'F' || ch == 'G')
- result = STRCONST("NAN");
- else
- result = STRCONST("nan");
- size = 3;
- flags &= ~ZEROPAD;
- break;
- }
flags |= FPT;
- dtoaresult = cvt(_double, prec, flags, &softsign,
- &expt, ch, &ndig);
- if (dtoaresult == NULL)
- goto oomem;
- if (convbuf != NULL)
- free(convbuf);
-#ifndef NARROW
- result = convbuf = __mbsconv(dtoaresult, -1, loc);
-#else
- /*XXX inefficient*/
- result = convbuf = strdup(dtoaresult);
-#endif
- if (result == NULL)
- goto oomem;
- __freedtoa(dtoaresult);
- if (softsign)
- sign = '-';
-#endif
- flags |= FPT;
if (ch == 'g' || ch == 'G') {
if (expt > -4 && expt <= prec) {
/* Make %[gG] smell like %[fF] */
@@ -2001,57 +1953,7 @@ __grow_type_table (size_t nextarg, enum
return 0;
}
-
#ifndef NO_FLOATING_POINT
-#ifndef WIDE_DOUBLE
-static char *
-cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch,
- int *length)
-{
- int mode, dsgn;
- char *digits, *bp, *rve;
-
- _DIAGASSERT(decpt != NULL);
- _DIAGASSERT(length != NULL);
- _DIAGASSERT(sign != NULL);
-
- if (ch == 'f') {
- mode = 3; /* ndigits after the decimal point */
- } else {
- /* To obtain ndigits after the decimal point for the 'e'
- * and 'E' formats, round to ndigits + 1 significant
- * figures.
- */
- if (ch == 'e' || ch == 'E') {
- ndigits++;
- }
- mode = 2; /* ndigits significant digits */
- }
-
- digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
- if (digits == NULL)
- return NULL;
- if (dsgn) {
- value = -value;
- *sign = '-';
- } else
- *sign = '\000';
- if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
- bp = digits + ndigits;
- if (ch == 'f') {
- if (*digits == '0' && value)
- *decpt = -ndigits + 1;
- bp += *decpt;
- }
- if (value == 0) /* kludge for __dtoa irregularity */
- rve = bp;
- while (rve < bp)
- *rve++ = '0';
- }
- *length = rve - digits;
- return digits;
-}
-#endif
static int
exponent(CHAR_T *p0, int expo, int fmtch)
From: Havard Eidnes <he@NetBSD.org>
To: gnats-bugs@netbsd.org, martin@duskware.de
Cc: lib-bug-people@netbsd.org, gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org, martin@NetBSD.org
Subject: Re: lib/57250: dtoa mishandles infinite doubles on 32bit big
endian machines
Date: Tue, 04 Apr 2023 21:22:27 +0200 (CEST)
...and here's a minimal test modification:
Index: t_printf.c
===================================================================
RCS file: /cvsroot/src/tests/lib/libc/stdio/t_printf.c,v
retrieving revision 1.8
diff -u -p -r1.8 t_printf.c
--- t_printf.c 11 Apr 2012 16:21:42 -0000 1.8
+++ t_printf.c 4 Apr 2023 19:21:28 -0000
@@ -35,6 +35,7 @@
#include <string.h>
#include <time.h>
#include <stdlib.h>
+#include <errno.h>
ATF_TC(snprintf_c99);
ATF_TC_HEAD(snprintf_c99, tc)
@@ -155,6 +156,49 @@ ATF_TC_BODY(snprintf_float, tc)
}
}
+ATF_TC(snprintf_double_a);
+ATF_TC_HEAD(snprintf_double_a, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test printf a format");
+}
+
+ATF_TC_BODY(snprintf_double_a, tc)
+{
+ char buf[1000];
+
+ snprintf(buf, sizeof buf, "%.3a", (double)10.6);
+ ATF_REQUIRE_STREQ("0x1.533p+3", buf);
+}
+
+/* is "long double" and "double" different? */
+#if (__LDBL_MANT_DIG__ != __DBL_MANT_DIG__) || \
+ (__LDBL_MAX_EXP__ != __DBL_MAX_EXP__)
+#define WIDE_DOUBLE
+#endif
+
+#ifndef WIDE_DOUBLE
+ATF_TC(pr57250_fix);
+ATF_TC_HEAD(pr57250_fix, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test for PR57250");
+}
+
+ATF_TC_BODY(pr57250_fix, tc)
+{
+ char *eptr;
+ char buf[1000];
+ long double ld;
+
+ errno = 0;
+ ld = strtold("1e309", &eptr);
+ ATF_CHECK(errno != 0);
+ ld = (double)ld;
+ ATF_CHECK(isfinite(ld) == 0);
+ snprintf(buf, sizeof buf, "%Lf\n", ld);
+ ATF_REQUIRE_STREQ(buf, "inf");
+}
+#endif
+
ATF_TC(sprintf_zeropad);
ATF_TC_HEAD(sprintf_zeropad, tc)
{
@@ -189,6 +233,10 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, snprintf_posarg_error);
ATF_TP_ADD_TC(tp, snprintf_float);
ATF_TP_ADD_TC(tp, sprintf_zeropad);
+ ATF_TP_ADD_TC(tp, snprintf_double_a);
+#ifndef WIDE_DOUBLE
+ ATF_TP_ADD_TC(tp, pr57250_fix);
+#endif
return atf_no_error();
}
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/57250 CVS commit: src/lib/libc
Date: Tue, 4 Apr 2023 15:26:06 -0400
Module Name: src
Committed By: christos
Date: Tue Apr 4 19:26:06 UTC 2023
Modified Files:
src/lib/libc/include: extern.h
src/lib/libc/stdio: Makefile.inc vfwprintf.c
Log Message:
PR/57250: Martin Husemann: dtoa mishandles infinite doubles on 32bit big
endian machines. When long double support was added, the old code was kept
for the regular double code. This code was never used because WIDE_DOUBLE
was always defined in the Makefile. Remove that old code, and conditionalize
the WIDE_DOUBLE code based on if long doubles are different than doubles on
the specific platform.
To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/lib/libc/include/extern.h
cvs rdiff -u -r1.47 -r1.48 src/lib/libc/stdio/Makefile.inc
cvs rdiff -u -r1.39 -r1.40 src/lib/libc/stdio/vfwprintf.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/57250 CVS commit: src/tests/lib/libc/stdio
Date: Tue, 4 Apr 2023 15:30:11 -0400
Module Name: src
Committed By: christos
Date: Tue Apr 4 19:30:11 UTC 2023
Modified Files:
src/tests/lib/libc/stdio: t_printf.c
Log Message:
Add a test for PR/57250 from Havard Eidnes
To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/tests/lib/libc/stdio/t_printf.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: PR/57250 CVS commit: src/tests/lib/libc/stdio
Date: Wed, 5 Apr 2023 17:25:42 +0200
There is one minor detail still different between the architectures
where double != long double and the ones where it is identical:
errno is set only when the types are identical.
The test program from the PR prints on i386:
> ./a.out 1e309
a.out: infinite
inf
but on macppc:
> ./a.out 1e309
a.out: errno: Result too large or too small
a.out: infinite
inf
I am not sure which variant is more correct :-)
Martin
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: PR/57250 CVS commit: src/tests/lib/libc/stdio
Date: Wed, 5 Apr 2023 19:54:09 +0200
Bah, I was confused (or the test program is) - output is now just as
expected. Any arch where 1e309 fits into a long double but not a double
should produce the two +Inf printouts but no errno.
Any arch where the 1e309 does not fit in a long double nor a double
should produce the errno and two +Inf printouts.
All seems fine.
Martin
State-Changed-From-To: open->closed
State-Changed-By: martin@NetBSD.org
State-Changed-When: Thu, 06 Apr 2023 14:52:52 +0000
State-Changed-Why:
Fixed, thanks!
From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/57250 CVS commit: [netbsd-10] src/lib/libc
Date: Mon, 17 Apr 2023 18:22:20 +0000
Module Name: src
Committed By: martin
Date: Mon Apr 17 18:22:20 UTC 2023
Modified Files:
src/lib/libc/include [netbsd-10]: extern.h
src/lib/libc/stdio [netbsd-10]: Makefile.inc vfwprintf.c
Log Message:
Pull up following revision(s) (requested by he in ticket #137):
lib/libc/stdio/Makefile.inc: revision 1.48
lib/libc/stdio/vfwprintf.c: revision 1.40
lib/libc/include/extern.h: revision 1.27
PR/57250: Martin Husemann: dtoa mishandles infinite doubles on 32bit big
endian machines. When long double support was added, the old code was kept
for the regular double code. This code was never used because WIDE_DOUBLE
was always defined in the Makefile. Remove that old code, and conditionalize
the WIDE_DOUBLE code based on if long doubles are different than doubles on
the specific platform.
To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.26.6.1 src/lib/libc/include/extern.h
cvs rdiff -u -r1.47 -r1.47.26.1 src/lib/libc/stdio/Makefile.inc
cvs rdiff -u -r1.39 -r1.39.2.1 src/lib/libc/stdio/vfwprintf.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/57250 CVS commit: [netbsd-10] src/tests/lib/libc/stdio
Date: Mon, 17 Apr 2023 18:24:52 +0000
Module Name: src
Committed By: martin
Date: Mon Apr 17 18:24:52 UTC 2023
Modified Files:
src/tests/lib/libc/stdio [netbsd-10]: t_printf.c
Log Message:
Pull up following revision(s) (requested by he in ticket #138):
tests/lib/libc/stdio/t_printf.c: revision 1.9
tests/lib/libc/stdio/t_printf.c: revision 1.10
Add a test for PR/57250 from Havard Eidnes
Fix the test for "inf" output, also include newline in printf format...
To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.8.42.1 src/tests/lib/libc/stdio/t_printf.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2023
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.