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] Fix risks of buf overflow in money_put


Hi,

checking again the various locale facets for such kind of risk, I have found two
more: the first is in money_put::do_put(long double), where
__convert_from_v("%.01Lf") is used to print into a __builtin_alloca-ted
temporary buffer; the second is in money_put::do_put(string), where a buffer is
used when adding the grouping chars.

Indeed, the testcase below segfaults if both of them are not fixed.

IMO, the former can be dealt with in full generality only by enlarging the
buffer to the real maximum expected size of the printed string. The latter,
luckily, is fixed much more easily, since, in fact, the actual size of the
integer part is known at that point.

Tested i686-pc-linux-gnu. Ok?

Ciao, Paolo.

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

2002-03-17  Paolo Carlini  <pcarlini@unitus.it>

        * include/bits/locale_facets.tcc
        (money_put::do_put(long double)): Fix dimensioning of
        temporary buffers to avoid risk of overruns.
        (money_put::do_put(string)): Same for the buffer used to
        add the grouping chars.
        * testsuite/22_locale/money_put_members_char.cc: Add test06.
        * testsuite/22_locale/money_put_members_char.cc: Ditto.

diff -urN 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 11 00:51:31 2002
+++ libstdc++-v3/include/bits/locale_facets.tcc Sun Mar 17 02:12:13 2002
@@ -1110,8 +1110,10 @@
     long double __units) const
     {
       const locale __loc = __io.getloc();
-      const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
-      const int __n = numeric_limits<long double>::digits10;
+      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);
@@ -1206,7 +1208,7 @@
                   : __mpf.thousands_sep();
     const char* __gbeg = __grouping.c_str();
     const char* __gend = __gbeg + __grouping.size();
-    const int __n = numeric_limits<long double>::digits10 * 2;
+    const int __n = (__end - __beg) * 2;
     _CharT* __ws2 = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) *
__n));
     _CharT* __ws_end = __add_grouping(__ws2, __sep, __gbeg,
           __gend, __beg, __end);
diff -urN libstdc++-v3-orig/testsuite/22_locale/money_put_members_char.cc
libstdc++-v3/testsuite/22_locale/money_put_members_char.cc
--- libstdc++-v3-orig/testsuite/22_locale/money_put_members_char.cc Wed Feb 20
22:06:40 2002
+++ libstdc++-v3/testsuite/22_locale/money_put_members_char.cc Sun Mar 17
01:37:23 2002
@@ -226,7 +226,7 @@
   oss.setf(ios_base::showbase);

   oss.str(empty);
- iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
+  iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
   string result3 = oss.str();
   VERIFY( result3 == "7.200.000.000,00 DEM ");

@@ -341,6 +341,33 @@
   VERIFY( fmt.str() == "*(1,234.56)" );
 }

+struct My_money_io_2 : public std::moneypunct<char,false>
+{
+  char_type do_thousands_sep() const { return ','; }
+  std::string do_grouping() const { return "\001"; }
+};
+
+// Make sure we can output a very big amount of money (with grouping too).
+void test06()
+{
+  using namespace std;
+  typedef ostreambuf_iterator<char> OutIt;
+
+  locale loc(locale::classic(), new My_money_io_2);
+
+  bool intl = false;
+
+  long double val = 1e50L;
+  const money_put<char,OutIt>& mp  =
+    use_facet<money_put<char, OutIt> >(loc);
+
+  ostringstream fmt;
+  fmt.imbue(loc);
+  OutIt out(fmt);
+  mp.put(out,intl,fmt,'*',val);
+  VERIFY( fmt );
+}
+
 int main()
 {
   test01();
@@ -348,5 +375,6 @@
   test03();
   test04();
   test05();
+  test06();
   return 0;
 }
diff -urN libstdc++-v3-orig/testsuite/22_locale/money_put_members_wchar_t.cc
libstdc++-v3/testsuite/22_locale/money_put_members_wchar_t.cc
--- libstdc++-v3-orig/testsuite/22_locale/money_put_members_wchar_t.cc Wed Feb
20 22:06:40 2002
+++ libstdc++-v3/testsuite/22_locale/money_put_members_wchar_t.cc Sun Mar 17
01:42:42 2002
@@ -226,7 +226,7 @@
   oss.setf(ios_base::showbase);

   oss.str(empty);
- iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
+  iterator_type os_it03 = mon_put.put(oss.rdbuf(), true, oss, ' ', digits1);
   wstring result3 = oss.str();
   VERIFY( result3 == L"7.200.000.000,00 DEM ");

@@ -340,6 +340,33 @@
   mp.put(out,intl,fmt,L'*',val);
   VERIFY( fmt.str() == L"*(1,234.56)" );
 }
+
+struct My_money_io_2 : public std::moneypunct<wchar_t,false>
+{
+  char_type do_thousands_sep() const { return L','; }
+  std::string do_grouping() const { return "\001"; }
+};
+
+// Make sure we can output a very big amount of money (with grouping too).
+void test06()
+{
+  using namespace std;
+  typedef ostreambuf_iterator<wchar_t> OutIt;
+
+  locale loc(locale::classic(), new My_money_io_2);
+
+  bool intl = false;
+
+  long double val = 1e50L;
+  const money_put<wchar_t,OutIt>& mp  =
+    use_facet<money_put<wchar_t, OutIt> >(loc);
+
+  wostringstream fmt;
+  fmt.imbue(loc);
+  OutIt out(fmt);
+  mp.put(out,intl,fmt,'*',val);
+  VERIFY( fmt );
+}
 #endif

 int main()
@@ -350,6 +377,7 @@
   test03();
   test04();
   test05();
+  test06();
 #endif
   return 0;
 }





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