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:

NetBSD Home
NetBSD PR Database Search

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