This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Use snprintf when available (take2)


Hi again,

this is the second take, incorporating Uli's nice solution for the unused
parameter problem. I have also updated some comments.

Again, tested i686-pc-linux-gnu, both --enable-c99 and --disable-c99.

Ok?

Ciao, Paolo.

//////////////

2002-03-19  Paolo Carlini  <pcarlini@unitus.it>
            Ulrich Drepper  <drepper@redhat.com>

        * src/locale-inst.cc (__convert_from_v): Add an additional
        __size parameter in the declarations.
        * 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 21:59:38 2002
*************** namespace std
*** 592,607 ****
        return __beg;
      }

!
!   // The following code uses sprintf() to convert floating point
!   // values for insertion into a stream.  An optimization would be to
!   // replace sprintf() with code that works directly on a wide buffer
!   // and then use __pad to do the padding. It would be good
!   // to replace sprintf() anyway to avoid accidental buffer overruns
!   // and to gain back the efficiency that C++ provides by knowing up
!   // front the type of the values to insert. This implementation
!   // follows the C++ standard fairly directly as outlined in 22.2.2.2
!   // [lib.locale.num.put]
    template<typename _CharT, typename _OutIter>
      template<typename _ValueT>
        _OutIter
--- 592,606 ----
        return __beg;
      }

!   // The following code uses snprintf (or sprintf(), when _GLIBCPP_USE_C99
!   // is not defined) to convert floating point values for insertion into a
!   // stream.  An optimization would be to replace them with code that works
!   // directly on a wide buffer and then use __pad to do the padding.
!   // It would be good to replace them anyway to gain back the efficiency
!   // that C++ provides by knowing up front the type of the values to insert.
!   // Also, sprintf is dangerous since may lead to accidental buffer overruns.
!   // This implementation follows the C++ standard fairly directly as
!   // outlined in 22.2.2.2 [lib.locale.num.put]
    template<typename _CharT, typename _OutIter>
      template<typename _ValueT>
        _OutIter
*************** 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;
--- 612,649 ----
   // 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);
        }

--- 656,666 ----
                                 : __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);
        }

--- 672,699 ----
         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);
--- 1149,1174 ----
      {
        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
*** 1894,1913 ****
       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;
      }

    // Construct correctly padded string, as per 22.2.2.2.2
    // Assumes
--- 1946,1984 ----
       const __c_locale& __cloc, int __base = 10);

    // Convert numeric value of type _Tv to string and return length of string.
+   // If snprintf is available use it, otherwise fall back to the unsafe sprintf
+   // which, in general, can be dangerous and should be avoided.
+ #ifdef _GLIBCPP_USE_C99
+   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)
+         __ret = snprintf(__out, __size, __fmt, __prec, __v);
+       else
+         __ret = snprintf(__out, __size, __fmt, __v);
+       setlocale(LC_ALL, __old);
+       return __ret;
+     }
+ #else
    template<typename _Tv>
      int
!     __convert_from_v(char* __out, const int, 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;
      }
+ #endif

    // Construct correctly padded string, as per 22.2.2.2.2
    // Assumes
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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]