ldtoa: don't restrict outbuf size to ndigits

https://cygwin.com/pipermail/cygwin/2021-November/249930.html
reported a regression introduce by using a dynamically sized local
char array in favor of a statically sized array.

Fix this by reverting to a statically sized array, using a small
buffer on the stack for a reasonable number of requested digits, a
big mallocated buffer otherwise.  This should work for small targets
as well, given that malloc is used in printf anyway right now.

This is *still* hopefully just a temporary measure, unless somebody
actually provides a new ldtoa.

Fixes: 4d90e53359 ("ldtoa: fix dropping too many digits from output")
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2021-11-22 13:57:16 +01:00
parent 1fda4aebd6
commit 68faeef4be
2 changed files with 28 additions and 10 deletions

View File

@ -33,10 +33,10 @@ void _IO_ldtostr (long double *, char *, int, int, char);
/* Number of bits of precision */
#define NBITS ((NI-4)*16)
/* Maximum number of decimal digits in ASCII conversion
* Take full possible size of output into account
*/
/* Maximum number of decimal digits in ASCII conversion */
#define NDEC 1023
/* Use static stack buffer for up to 44 digits */
#define NDEC_SML 44
/* The exponent of 1.0 */
#define EXONE (0x3fff)
@ -2794,6 +2794,8 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits,
LDPARMS rnd;
LDPARMS *ldp = &rnd;
char *outstr;
char outbuf_sml[NDEC_SML + MAX_EXP_DIGITS + 10];
char *outbuf = outbuf_sml;
union uconv du;
du.d = d;
@ -2836,11 +2838,22 @@ _ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits,
ndigits = 20;
/* This sanity limit must agree with the corresponding one in etoasc, to
keep straight the returned value of outexpon. */
keep straight the returned value of outexpon. Note that we use a dynamic
limit now, either NDEC or NDEC_SML, depending on ndigits. See the usage
of "my_NDEC" in etoasc. */
if (ndigits > NDEC)
ndigits = NDEC;
char outbuf[ndigits + MAX_EXP_DIGITS + 10];
/* Allocate buffer if more than NDEC_SML digits are requested. */
if (ndigits > NDEC_SML)
{
outbuf = (char *) _malloc_r (ptr, NDEC + MAX_EXP_DIGITS + 10);
if (!outbuf)
{
ndigits = NDEC_SML;
outbuf = outbuf_sml;
}
}
etoasc (e, outbuf, ndigits, mode, ldp);
s = outbuf;
@ -2933,6 +2946,9 @@ stripspaces:
if (rve)
*rve = outstr + (s - outbuf);
if (outbuf != outbuf_sml)
_free_r (ptr, outbuf);
return outstr;
}
@ -2987,6 +3003,7 @@ etoasc (short unsigned int *x, char *string, int ndigits, int outformat,
char *s, *ss;
unsigned short m;
unsigned short *equot = ldp->equot;
int my_NDEC = (ndigits > NDEC_SML) ? NDEC : NDEC_SML;
ndigs = ndigits;
rndsav = ldp->rndprc;
@ -3112,9 +3129,7 @@ tnzro:
else
{
emovi (y, w);
/* Note that this loop does not access the incoming string array,
* which may be shorter than NDEC + 1 bytes! */
for (i = 0; i < NDEC + 1; i++)
for (i = 0; i < my_NDEC + 1; i++)
{
if ((w[NI - 1] & 0x7) != 0)
break;
@ -3190,8 +3205,8 @@ isone:
else if( ndigs < 0 )
ndigs = 0;
*/
if (ndigs > NDEC)
ndigs = NDEC;
if (ndigs > my_NDEC)
ndigs = my_NDEC;
if (digit == 10)
{
*s++ = '1';

View File

@ -34,3 +34,6 @@ Bug Fixes
- Fix two bugs in raise(2).
Addresses: https://cygwin.com/pipermail/cygwin/2021-November/249973.html
- Fix regression in printf introduced with Cygwin 3.3.2.
Addresses: https://cygwin.com/pipermail/cygwin/2021-November/249930.html