This is the mail archive of the
cygwin@cygwin.com
mailing list for the Cygwin project.
Re: Heads up: *possible* bug in cygwin
- From: Charles Wilson <cwilson at ece dot gatech dot edu>
- To: cygwin at cygwin dot com
- Date: Wed, 01 Jan 2003 23:36:49 -0500
- Subject: Re: Heads up: *possible* bug in cygwin
- References: <E18PoeB-0000fC-00@quimby.gnus.org> <3E05BD05.5090408@ece.gatech.edu> <3E0DDE19.1060903@ece.gatech.edu> <3E10A7AE.20405@ece.gatech.edu> <3E10C29B.2010709@ece.gatech.edu> <3E111AAF.3090008@ece.gatech.edu> <20021231043913.GA26944@redhat.com> <3E11AD26.8050506@ece.gatech.edu> <20021231175349.GC6542@redhat.com> <3E123A28.8030705@ece.gatech.edu> <1041383123.6526.13.camel@lifelesswks> <3E137A39.9050204@ece.gatech.edu>
Turns out, the problem IS in newlib.
First, create a buffer of the appropriate length:
buffer = g_new (gchar, g_printf_string_upper_bound (format, args1));
And then format the data into that buffer.
vsprintf (buffer, format, args2);
But the buffer isn't long enough, so the actual problem is *probably*
somewhere in the g_printf_string_upper_bound() routine, that computes
the appropriate length.
Well, not exactly. g_printf_string_upper_bound returns 30k, which is
more than sufficient, actually. An annotated "stack trace" is below.
(ignore the stuff about impure_ptr, I wrote that stuff when I thought
there was a problem with insuffient memory allocation in that structure,
as used by *printf. I was both right and wrong, but impure_ptr is not
the problem...)
vsprintf
initializes a FILE variable f. Sets f._data = _impure_ptr
calls vfprintf(&f, ....)
vfprintf
makes sure f is good (which it will be, in this case)
calls _vfprintf_r(f->_data, ...) which is simply
_vfprintf_r(impure_ptr, ...)
_vfprintf_r
does the basic work. When the fmt string has a %f or other floating
point specifier, it calls cvt(data, ...) to do the actual formatting.
data is simply impure_ptr.
cvt
sets 'char *digits' to _ldtoa_r(data, ....) [again, data is our
impure_ptr.)
_ldtoa_r
first off , enforces a limit on ndigits of 42 on cygwin (see ldtoa.c,
#define NDEC for the algorithm). So 10000 is right out. However, this
is the problem:
cvt doesn't know that _ldtoa_r overrode ndigits to a "mere" 42. So, in
this code (part of cvt()):
1168 digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
1169 #endif /* !_NO_LONGDBL */
1170
1171 if ((ch != 'g' && ch != 'G') || flags & ALT)
1172 bp = digits + ndigits;
we set bp to something WAY past the end of digits. Since rve points to
the actual end of digits (where the '\0' is)...
1173 if (ch == 'f') {
1174 if (*digits == '0' && value)
1175 *decpt = -ndigits + 1;
1176 bp += *decpt;
1177 }
1178 if (value == 0)
1179 rve = bp;
1180 while (rve < bp)
1181 *rve++ = '0';
and then try to put 0's into digits[43...10000] in the while loop (lines
1180 and 1181). But, there were only 24 + (2^3-1)*4 == 52 bytes
allocated for digits.
I'm not sure what the correct fix is...should ndigits be passed by
reference to _ldtoa_r, so that cvt "knows" that it got changed? (Ditto
pass-by-reference to cvt so that vfprintf_r knows about the override as
well). This changes the signature of these two (admittedly internal)
routines, but I'm not sure of the "ripple effects" such a change might
cause.
Or is this a case of "doctor, it hurts when I do this?" "Don't call
printf with prec specifiers greater than 42, then."
--Chuck
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/