possible snprintf() regression in 3.3.2
Thu Nov 18 00:06:49 GMT 2021
On Wed, Nov 17, 2021 at 01:27:55PM +0100, Corinna Vinschen via Cygwin wrote:
> On Nov 17 18:21, Takashi Yano via Cygwin wrote:
> > On Wed, 17 Nov 2021 11:37:18 +1100
> > Tony Cook wrote:
> > > This came up from regression testing perl.
> > >
> > > Regression testing of perl @4a1b9dd524007193213d3919d6a331109608b90c
> > > used (from uname):
> > > [...]
> > I found the caused by the commit:
> > commit 4d90e5335914551862831de3e02f6c102b78435b
> > Author: Corinna Vinschen <email@example.com>
> > Date: Thu Nov 4 11:30:44 2021 +0100
> > ldtoa: fix dropping too many digits from output
> > ldtoa cuts the number of digits it returns based on a computation of
> > number of supported bits (144) divide by log10(2). Not only is the
> > integer approximation of log10(2) ~= 8/27 missing a digit here, it
> > also fails to take really small double and long double values into
> > account.
> > Allow for the full potential precision of long double values. At the
> > same time, change the local string array allocation to request only as
> > much bytes as necessary to support the caller-requested number of
> > digits, to keep the stack size low on small targets.
> > In the long run a better fix would be to switch to gdtoa, as the BSD
> > variants, as well as Mingw64 do.
> > Signed-off-by: Corinna Vinschen <firstname.lastname@example.org>
> > Reverting this commit solves the problem.
> > Corinna, could you please have a look?
> I don't have a good solution. The old ldtoa code is lacking, for
> switching newlib to gdtoa I simply don't have the time. On the newlib
> list was a short discussion starting at
> https://sourceware.org/pipermail/newlib/2021/018626.html but nothing
> came out of it yet.
> Patches gratefully accepted (except just reverting the above change).
>From what I can tell the problem has nothing to do with the extra
precision, but has to do with misusing ndigits for the buffer size
with a %f format string, leading to a buffer overflow.
At entry to _ldtoa_r() ndigits is 9, but for a %f format with a large
number the number of digits is more closely related to the magnitude
of the number, not ndigits.
With the input number (9e99) and the supplied format I'd expect 109
characters output, but outbuf is only:
ndigits + MAX_EXP_DIGITS + 10 = 9 + 5 + 10 = 24
characters in length.
More information about the Cygwin