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] Partial fix for libstdc++/17038


Hi,

this is only a partial fix for mainline and 3_4: in my opinion the problem
cannot be really solved without breaking the API/ABI: __timepunct::_M_put
must return an integer.
Anyway, this is some preliminary, useful, work:
1- A testcase needing 72 chars, vs 64, the current size of the buffer: I
   have enlarged the latter to 128.
2- Minimal, but really needed error checking: if strftime/wcsftime
   fails it is compulsory to null terminate __s anyway since later
   we are calling traits::length on it!
3- A FIXME comment about __timepunct::_M_put ;)

Tested x86/x86_64-linux, gnu/generic locale models.

Paolo.

/////////////////
2004-08-25  Paolo Carlini  <pcarlini@suse.de>

	PR libstdc++/17038 (partial)
	* include/bits/locale_facets.tcc (time_put<>::do_put): Increase
	__maxlen to 128.
	* include/bits/locale_facets.h (class __timepunct): Add FIXME
	comment about _M_put.
	* config/locale/generic/time_members.cc (_M_put): Always null
	terminate __s.
	* config/locale/gnu/time_members.cc (_M_put): Likewise.
	* testsuite/22_locale/time_put/put/char/17038.cc: New.
	* testsuite/22_locale/time_put/put/wchar_t/17038.cc: New.
diff -urN libstdc++-v3-orig/config/locale/generic/time_members.cc libstdc++-v3/config/locale/generic/time_members.cc
--- libstdc++-v3-orig/config/locale/generic/time_members.cc	2004-04-08 01:13:31.000000000 +0200
+++ libstdc++-v3/config/locale/generic/time_members.cc	2004-08-25 20:28:59.000000000 +0200
@@ -46,9 +46,12 @@
     {
       char* __old = strdup(setlocale(LC_ALL, NULL));
       setlocale(LC_ALL, _M_name_timepunct);
-      strftime(__s, __maxlen, __format, __tm);
+      const size_t __len = strftime(__s, __maxlen, __format, __tm);
       setlocale(LC_ALL, __old);
       free(__old);
+      // Make sure __s is null terminated.
+      if (__len == 0)
+	__s[0] = '\0';
     }
 
   template<> 
@@ -125,9 +128,12 @@
     {
       char* __old = strdup(setlocale(LC_ALL, NULL));
       setlocale(LC_ALL, _M_name_timepunct);
-      wcsftime(__s, __maxlen, __format, __tm);
+      const size_t __len = wcsftime(__s, __maxlen, __format, __tm);
       setlocale(LC_ALL, __old);
       free(__old);
+      // Make sure __s is null terminated.
+      if (__len == 0)
+	__s[0] = L'\0';      
     }
 
   template<> 
diff -urN libstdc++-v3-orig/config/locale/gnu/time_members.cc libstdc++-v3/config/locale/gnu/time_members.cc
--- libstdc++-v3-orig/config/locale/gnu/time_members.cc	2004-06-18 12:54:44.000000000 +0200
+++ libstdc++-v3/config/locale/gnu/time_members.cc	2004-08-25 20:28:10.000000000 +0200
@@ -46,14 +46,18 @@
 	   const tm* __tm) const
     {
 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
-      __strftime_l(__s, __maxlen, __format, __tm, _M_c_locale_timepunct);
+      const size_t __len = __strftime_l(__s, __maxlen, __format, __tm,
+					_M_c_locale_timepunct);
 #else
       char* __old = strdup(setlocale(LC_ALL, NULL));
       setlocale(LC_ALL, _M_name_timepunct);
-      strftime(__s, __maxlen, __format, __tm);
+      const size_t __len = strftime(__s, __maxlen, __format, __tm);
       setlocale(LC_ALL, __old);
       free(__old);
 #endif
+      // Make sure __s is null terminated.
+      if (__len == 0)
+	__s[0] = '\0';
     }
 
   template<> 
@@ -195,14 +199,18 @@
 	   const tm* __tm) const
     {
 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
-      __wcsftime_l(__s, __maxlen, __format, __tm, _M_c_locale_timepunct);
+      const size_t __len = __wcsftime_l(__s, __maxlen, __format, __tm,
+					_M_c_locale_timepunct);
 #else
       char* __old = strdup(setlocale(LC_ALL, NULL));
       setlocale(LC_ALL, _M_name_timepunct);
-      wcsftime(__s, __maxlen, __format, __tm);
+      const size_t __len = wcsftime(__s, __maxlen, __format, __tm);
       setlocale(LC_ALL, __old);
       free(__old);
 #endif
+      // Make sure __s is null terminated.
+      if (__len == 0)
+	__s[0] = L'\0';
     }
 
   template<> 
diff -urN libstdc++-v3-orig/include/bits/locale_facets.h libstdc++-v3/include/bits/locale_facets.h
--- libstdc++-v3-orig/include/bits/locale_facets.h	2004-05-23 01:46:32.000000000 +0200
+++ libstdc++-v3/include/bits/locale_facets.h	2004-08-25 19:18:13.000000000 +0200
@@ -2834,6 +2834,8 @@
       explicit
       __timepunct(__c_locale __cloc, const char* __s, size_t __refs = 0);
 
+      // FIXME: for error checking purposes _M_put should return the return
+      // value of strftime/wcsftime.
       void
       _M_put(_CharT* __s, size_t __maxlen, const _CharT* __format,
 	     const tm* __tm) const;
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	2004-08-22 19:55:50.000000000 +0200
+++ libstdc++-v3/include/bits/locale_facets.tcc	2004-08-25 19:18:23.000000000 +0200
@@ -2246,7 +2246,7 @@
 
       // NB: This size is arbitrary. Should this be a data member,
       // initialized at construction?
-      const size_t __maxlen = 64;
+      const size_t __maxlen = 128;
       char_type* __res = 
        static_cast<char_type*>(__builtin_alloca(sizeof(char_type) * __maxlen));
 
diff -urN libstdc++-v3-orig/testsuite/22_locale/time_put/put/char/17038.cc libstdc++-v3/testsuite/22_locale/time_put/put/char/17038.cc
--- libstdc++-v3-orig/testsuite/22_locale/time_put/put/char/17038.cc	1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/22_locale/time_put/put/char/17038.cc	2004-08-25 19:47:43.000000000 +0200
@@ -0,0 +1,63 @@
+// 2004-08-25  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2004 Free Software Foundation
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 22.2.5.3.1 time_put members
+
+#include <locale>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+// libstdc++/17038
+void test01()
+{
+  using namespace std;
+  typedef ostreambuf_iterator<char> iterator_type;
+
+  bool test __attribute__((unused)) = true;
+
+  // create "C" time objects
+  tm time1 = { 0, 0, 12, 4, 3, 71, 0, 93, 0 };
+
+  // basic construction
+  locale loc_c = locale::classic();
+  locale loc_in = __gnu_test::try_named_locale("ta_IN");
+  assert( loc_in != loc_c );
+
+  // create an ostream-derived object, cache the time_put facet
+  ostringstream oss;
+  oss.imbue(loc_in);
+  const time_put<char>& tim_put =
+    use_facet<time_put<char> >(oss.getloc()); 
+
+  iterator_type os_it01 = tim_put.put(oss.rdbuf(), oss, '*', &time1, 'c');
+  string result1 = oss.str();
+
+  char time_buffer[128];
+  setlocale(LC_ALL, "ta_IN");
+  VERIFY( strftime(time_buffer, 128, "%c", &time1) );
+  
+  VERIFY( result1 == time_buffer );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff -urN libstdc++-v3-orig/testsuite/22_locale/time_put/put/wchar_t/17038.cc libstdc++-v3/testsuite/22_locale/time_put/put/wchar_t/17038.cc
--- libstdc++-v3-orig/testsuite/22_locale/time_put/put/wchar_t/17038.cc	1970-01-01 01:00:00.000000000 +0100
+++ libstdc++-v3/testsuite/22_locale/time_put/put/wchar_t/17038.cc	2004-08-25 19:47:26.000000000 +0200
@@ -0,0 +1,63 @@
+// 2004-08-25  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2004 Free Software Foundation
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 22.2.5.3.1 time_put members
+
+#include <locale>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+// libstdc++/17038
+void test01()
+{
+  using namespace std;
+  typedef ostreambuf_iterator<wchar_t> iterator_type;
+
+  bool test __attribute__((unused)) = true;
+
+  // create "C" time objects
+  tm time1 = { 0, 0, 12, 4, 3, 71, 0, 93, 0 };
+
+  // basic construction
+  locale loc_c = locale::classic();
+  locale loc_in = __gnu_test::try_named_locale("ta_IN");
+  assert( loc_in != loc_c );
+
+  // create an ostream-derived object, cache the time_put facet
+  wostringstream oss;
+  oss.imbue(loc_in);
+  const time_put<wchar_t>& tim_put =
+    use_facet<time_put<wchar_t> >(oss.getloc()); 
+
+  iterator_type os_it01 = tim_put.put(oss.rdbuf(), oss, L'*', &time1, 'c');
+  wstring result1 = oss.str();
+
+  wchar_t time_buffer[128];
+  setlocale(LC_ALL, "ta_IN");
+  VERIFY( wcsftime(time_buffer, 128, L"%c", &time1) );
+  
+  VERIFY( result1 == time_buffer );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}

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