This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[PATCH] Use __snprintf when available
- From: Paolo Carlini <pcarlini at unitus dot it>
- To: libstdc++ at gcc dot gnu dot org
- Cc: bkoz at redhat dot com
- Date: Tue, 19 Mar 2002 18:58:22 +0100
- Subject: [PATCH] Use __snprintf when available
Hi,
below you will find the patch we have discussed yesterday. I have tested it
on i686-pc-linux-gnu, both --enable-c99 and --disable-c99 with no regressions.
When snprintf is available the staging buffers are usually just a few tens of
bytes large but can become as large as the available memory ;-) in case of
need. When snprintf is not available, for the sake of correctness the staging
buffers are typically much bigger but there are no risks of overruns as far as
I can tell.
There are at least two open issues, however:
1- Minor, but annoying: I could not manage to use __attribute__((__unused__))
for function parameters. Indeed, the following example triggers a parse error
at line #1:
f(int __size __attribute__ ((__unused__)), int i)
{
int j __attribute__ ((__unused__));
return i;
}
Therefore I had to resort to my horrible "if(__size);" trick :-(
Suggestions?
2- Autoconf issues, which seem to me really of two different kinds:
* Are there any actual systems which make available a C99-conforming
snprintf but which do not pass the tests for _GLIBCPP_USE_C99 enabled?
I think Loren in principle is interested in supporting them.
* Are there any systems passing the current suite of tests for
_GLIBCPP_USE_C99 but in fact having a non-conforming snprintf?
Ciao,
Paolo.
///////////////////
2002-03-19 Paolo Carlini <pcarlini@unitus.it>
* src/locale-inst.cc (__convert_from_v): Adjust declarations,
adding an additional __size parameter.
* include/bits/locale_facets.tcc
(__convert_from_v): When available (that is,
_GLIBCPP_USE_C99 defined) use snprintf instead of sprintf.
(num_put::_M_convert_float): Depending on _GLIBCPP_USE_C99
being defined or not, call and use __convert_from_v in the
appropriate way.
(num_put::_M_convert_int): Same here.
(money_put::do_put(long double)): Same here.
diff -prN libstdc++-v3-orig/include/bits/locale_facets.tcc
libstdc++-v3/include/bits/locale_facets.tcc
*** libstdc++-v3-orig/include/bits/locale_facets.tcc Mon Mar 18 00:27:14 2002
--- libstdc++-v3/include/bits/locale_facets.tcc Tue Mar 19 14:47:39 2002
*************** namespace std
*** 613,625 ****
// we get the full available precision.
const int __max_digits = numeric_limits<_ValueT>::digits10 + 1;
streamsize __prec = __io.precision();
! // Protect against sprintf() buffer overflows.
if (__prec > static_cast<streamsize>(__max_digits))
__prec = static_cast<streamsize>(__max_digits);
// Long enough for the max format spec.
char __fbuf[16];
// Consider the possibility of long ios_base::fixed outputs
const bool __fixed = __io.flags() & ios_base::fixed;
const int __max_exp = numeric_limits<_ValueT>::max_exponent10;
--- 613,650 ----
// we get the full available precision.
const int __max_digits = numeric_limits<_ValueT>::digits10 + 1;
streamsize __prec = __io.precision();
!
if (__prec > static_cast<streamsize>(__max_digits))
__prec = static_cast<streamsize>(__max_digits);
// Long enough for the max format spec.
char __fbuf[16];
+ // [22.2.2.2.2] Stage 1, numeric conversion to character.
+ int __len;
+ #ifdef _GLIBCPP_USE_C99
+ // First try a buffer perhaps big enough (for sure sufficient for
+ // non-ios_base::fixed outputs)
+ int __cs_size = __max_digits * 3;
+ char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
+
+ const bool __fp = _S_format_float(__io, __fbuf, __mod, __prec);
+ if (__fp)
+ __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale, __prec);
+ else
+ __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
+
+ // If the buffer was not large enough, try again with the correct size.
+ if (__len >= __cs_size)
+ {
+ __cs_size = __len + 1;
+ __cs = static_cast<char*>(__builtin_alloca(__cs_size));
+ if (__fp)
+ __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale, __prec);
+ else
+ __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
+ }
+ #else
// Consider the possibility of long ios_base::fixed outputs
const bool __fixed = __io.flags() & ios_base::fixed;
const int __max_exp = numeric_limits<_ValueT>::max_exponent10;
*************** namespace std
*** 632,643 ****
: __max_digits * 3;
char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
- int __len;
- // [22.2.2.2.2] Stage 1, numeric conversion to character.
if (_S_format_float(__io, __fbuf, __mod, __prec))
! __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale, __prec);
else
! __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale);
return _M_widen_float(__s, __io, __fill, __cs, __len);
}
--- 657,667 ----
: __max_digits * 3;
char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
if (_S_format_float(__io, __fbuf, __mod, __prec))
! __len = __convert_from_v(__cs, 0, __fbuf, __v, _S_c_locale, __prec);
else
! __len = __convert_from_v(__cs, 0, __fbuf, __v, _S_c_locale);
! #endif
return _M_widen_float(__s, __io, __fill, __cs, __len);
}
*************** namespace std
*** 649,661 ****
char __modl, _ValueT __v) const
{
// [22.2.2.2.2] Stage 1, numeric conversion to character.
! // Leave room for "+/-," "0x," and commas. This size is
! // arbitrary, but should work.
! char __cs[64];
// Long enough for the max format spec.
char __fbuf[16];
_S_format_int(__io, __fbuf, __mod, __modl);
! int __len = __convert_from_v(__cs, __fbuf, __v, _S_c_locale);
return _M_widen_int(__s, __io, __fill, __cs, __len);
}
--- 673,700 ----
char __modl, _ValueT __v) const
{
// [22.2.2.2.2] Stage 1, numeric conversion to character.
!
// Long enough for the max format spec.
char __fbuf[16];
_S_format_int(__io, __fbuf, __mod, __modl);
! #ifdef _GLIBCPP_USE_C99
! // First try a buffer perhaps big enough.
! int __cs_size = 64;
! char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
! int __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
! // If the buffer was not large enough, try again with the correct size.
! if (__len >= __cs_size)
! {
! __cs_size = __len + 1;
! __cs = static_cast<char*>(__builtin_alloca(__cs_size));
! __len = __convert_from_v(__cs, __cs_size, __fbuf, __v, _S_c_locale);
! }
! #else
! // Leave room for "+/-," "0x," and commas. This size is
! // arbitrary, but should be largely sufficient.
! char __cs[128];
! int __len = __convert_from_v(__cs, 0, __fbuf, __v, _S_c_locale);
! #endif
return _M_widen_int(__s, __io, __fill, __cs, __len);
}
*************** namespace std
*** 1111,1122 ****
{
const locale __loc = __io.getloc();
const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
// max_exponent10 + 1 for the integer part, + 4 for sign, decimal point,
// decimal digit, '\0'.
! const int __n = numeric_limits<long double>::max_exponent10 + 5;
! char* __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __n));
! _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __n));
! int __len = __convert_from_v(__cs, "%.01Lf", __units, _S_c_locale);
__ctype.widen(__cs, __cs + __len, __ws);
string_type __digits(__ws);
return this->do_put(__s, __intl, __io, __fill, __digits);
--- 1150,1175 ----
{
const locale __loc = __io.getloc();
const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
+ #ifdef _GLIBCPP_USE_C99
+ // First try a buffer perhaps big enough.
+ int __cs_size = 64;
+ char* __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __cs_size));
+ int __len = __convert_from_v(__cs, __cs_size, "%.01Lf", __units, _S_c_locale);
+ // If the buffer was not large enough, try again with the correct size.
+ if (__len >= __cs_size)
+ {
+ __cs_size = __len + 1;
+ __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __cs_size));
+ __len = __convert_from_v(__cs, __cs_size, "%.01Lf", __units, _S_c_locale);
+ }
+ #else
// max_exponent10 + 1 for the integer part, + 4 for sign, decimal point,
// decimal digit, '\0'.
! const int __cs_size = numeric_limits<long double>::max_exponent10 + 5;
! char* __cs = static_cast<char*>(__builtin_alloca(sizeof(char) * __cs_size));
! int __len = __convert_from_v(__cs, 0, "%.01Lf", __units, _S_c_locale);
! #endif
! _CharT* __ws = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __cs_size));
__ctype.widen(__cs, __cs + __len, __ws);
string_type __digits(__ws);
return this->do_put(__s, __intl, __io, __fill, __digits);
*************** namespace std
*** 1893,1911 ****
__convert_to_v(const char* __in, _Tv& __out, ios_base::iostate& __err,
const __c_locale& __cloc, int __base = 10);
! // Convert numeric value of type _Tv to string and return length of string.
template<typename _Tv>
int
! __convert_from_v(char* __out, const char* __fmt, _Tv __v,
const __c_locale&, int __prec = -1)
{
int __ret;
const char* __old = setlocale(LC_ALL, "C");
if (__prec >= 0)
! __ret = sprintf(__out, __fmt, __prec, __v);
else
! __ret = sprintf(__out, __fmt, __v);
setlocale(LC_ALL, __old);
return __ret;
}
--- 1946,1973 ----
__convert_to_v(const char* __in, _Tv& __out, ios_base::iostate& __err,
const __c_locale& __cloc, int __base = 10);
! // Convert numeric value of type _Tv to string and return length of string
template<typename _Tv>
int
! __convert_from_v(char* __out, const int __size, const char* __fmt, _Tv __v,
const __c_locale&, int __prec = -1)
{
int __ret;
const char* __old = setlocale(LC_ALL, "C");
if (__prec >= 0)
! #ifdef _GLIBCPP_USE_C99
! __ret = snprintf(__out, __size, __fmt, __prec, __v);
! #else
! __ret = sprintf(__out, __fmt, __prec, __v);
! #endif
else
! #ifdef _GLIBCPP_USE_C99
! __ret = snprintf(__out, __size, __fmt, __v);
! #else
! __ret = sprintf(__out, __fmt, __v);
! #endif
setlocale(LC_ALL, __old);
+ if (__size); // Only to suppress a warning unused when !C99.
return __ret;
}
diff -prN libstdc++-v3-orig/src/locale-inst.cc libstdc++-v3/src/locale-inst.cc
*** libstdc++-v3-orig/src/locale-inst.cc Fri Mar 8 07:05:20 2002
--- libstdc++-v3/src/locale-inst.cc Tue Mar 19 00:40:04 2002
*************** namespace std
*** 461,488 ****
template
int
! __convert_from_v(char*, const char*, double, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, long double, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, unsigned long,
const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, long long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const char*, unsigned long long,
const __c_locale&, int);
template
--- 461,488 ----
template
int
! __convert_from_v(char*, const int, const char*, double, const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, long double, const __c_locale&,
int);
template
int
! __convert_from_v(char*, const int, const char*, long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, unsigned long,
const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, long long, const __c_locale&, int);
template
int
! __convert_from_v(char*, const int, const char*, unsigned long long,
const __c_locale&, int);
template