re PR libstdc++/12352 (Exception safety problems in src/localename.cc)
authorPaolo Carlini <pcarlini@unitus.it>
Fri, 26 Sep 2003 00:22:01 +0000 (02:22 +0200)
committerPaolo Carlini <paolo@gcc.gnu.org>
Fri, 26 Sep 2003 00:22:01 +0000 (00:22 +0000)
2003-09-25  Paolo Carlini  <pcarlini@unitus.it>

PR libstdc++/12352
* src/localename.cc (locale::_Impl::_Impl(const _Impl&,
size_t)): Don't leak if memory allocations for _M_facets,
_M_caches, and _M_names fail.
(locale::_Impl::_Impl(const char*, size_t)): Ditto.
(locale::_Impl::_M_replace_categories(const _Impl*,
category)): Ditto.
(locale::_Impl::_M_install_facet(const locale::id*,
const facet*)): Ditto.
* include/bits/locale_classes.h (locale::locale(const locale&,
_Facet*)): Don't leak memory.
* testsuite/22_locale/locale/cons/12352.cc: New, from the PR.

* src/localename.cc (locale::_Impl::_Impl(facet**, size_t,
bool)): Qualify with std:: strcpy, tweak.
* include/bits/locale_classes.h
(locale::_Impl::_M_check_same_name): Qualify strcmp.

From-SVN: r71808

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/locale_classes.h
libstdc++-v3/src/localename.cc
libstdc++-v3/testsuite/22_locale/locale/cons/12352.cc [new file with mode: 0644]

index 2ac17ed..7729b7b 100644 (file)
@@ -1,3 +1,23 @@
+2003-09-25  Paolo Carlini  <pcarlini@unitus.it>
+
+       PR libstdc++/12352
+       * src/localename.cc (locale::_Impl::_Impl(const _Impl&,
+       size_t)): Don't leak if memory allocations for _M_facets,
+       _M_caches, and _M_names fail.
+       (locale::_Impl::_Impl(const char*, size_t)): Ditto.
+       (locale::_Impl::_M_replace_categories(const _Impl*,
+       category)): Ditto.
+       (locale::_Impl::_M_install_facet(const locale::id*,
+       const facet*)): Ditto.
+       * include/bits/locale_classes.h (locale::locale(const locale&,
+       _Facet*)): Don't leak memory.
+       * testsuite/22_locale/locale/cons/12352.cc: New, from the PR.
+
+       * src/localename.cc (locale::_Impl::_Impl(facet**, size_t,
+       bool)): Qualify with std:: strcpy, tweak.
+       * include/bits/locale_classes.h
+       (locale::_Impl::_M_check_same_name): Qualify strcmp.
+
 2003-09-25  Brad Spencer  <spencer@infointeractive.com>
 
        PR libstdc++/6072
index b93cfb3..49ece4c 100644 (file)
@@ -346,7 +346,7 @@ namespace std
     {
       bool __ret = true;
       for (size_t __i = 0; __ret && __i < _S_categories_size - 1; ++__i)
-       __ret &= (strcmp(_M_names[__i], _M_names[__i + 1]) == 0);
+       __ret &= (std::strcmp(_M_names[__i], _M_names[__i + 1]) == 0);
       return __ret;
     }
 
@@ -379,13 +379,30 @@ namespace std
     locale::locale(const locale& __other, _Facet* __f)
     {
       _M_impl = new _Impl(*__other._M_impl, 1);
-      _M_impl->_M_install_facet(&_Facet::id, __f);
-      for (size_t __i = 0; __i < _S_categories_size; ++__i)
+
+      char* _M_tmp_names[_S_categories_size];
+      size_t __i = 0;
+      try
+       {
+         for (; __i < _S_categories_size; ++__i)
+           {
+             _M_tmp_names[__i] = new char[2];
+             std::strcpy(_M_tmp_names[__i], "*");
+           }
+         _M_impl->_M_install_facet(&_Facet::id, __f);
+       }
+      catch(...)
+       {
+         delete _M_impl;
+         for (size_t __j = 0; __j < __i; ++__j)
+           delete [] _M_tmp_names[__j];          
+         __throw_exception_again;
+       }
+
+      for (size_t __k = 0; __k < _S_categories_size; ++__k)
        {
-         delete [] _M_impl->_M_names[__i];
-         char* __new = new char[2];
-         std::strcpy(__new, "*");
-         _M_impl->_M_names[__i] = __new;
+         delete [] _M_impl->_M_names[__k];
+         _M_impl->_M_names[__k] = _M_tmp_names[__k];
        }
     }
 } // namespace std
index d428290..866e897 100644 (file)
@@ -44,7 +44,7 @@ namespace __gnu_cxx
   extern numpunct<char>                        numpunct_c;
   extern num_get<char>                                 num_get_c;
   extern num_put<char>                                 num_put_c;  
-extern codecvt<char, char, mbstate_t>          codecvt_c;
+  extern codecvt<char, char, mbstate_t>                codecvt_c;
   extern moneypunct<char, false>               moneypunct_cf;
   extern moneypunct<char, true>                moneypunct_ct;
   extern money_get<char>                       money_get_c;
@@ -111,55 +111,48 @@ namespace std
   _Impl(const _Impl& __imp, size_t __refs)
   : _M_references(__refs), _M_facets_size(__imp._M_facets_size)
   {
+    _M_facets = _M_caches = 0;
+    _M_names = 0;
     try
-      { 
+      {
        _M_facets = new const facet*[_M_facets_size]; 
-       for (size_t __i = 0; __i < _M_facets_size; ++__i)
-         _M_facets[__i] = 0;
+       _M_caches = new const facet*[_M_facets_size];
+       _M_names = new char*[_S_categories_size];
       }
-    catch(...) 
+    catch(...)
       {
        delete [] _M_facets;
+       delete [] _M_caches;            
        __throw_exception_again;
       }
+
     for (size_t __i = 0; __i < _M_facets_size; ++__i)
       {
        _M_facets[__i] = __imp._M_facets[__i];
+       _M_caches[__i] = __imp._M_caches[__i];
        if (_M_facets[__i])
          _M_facets[__i]->_M_add_reference();
-      }
-
-    try 
-      {
-       _M_caches = new const facet*[_M_facets_size];
-      }
-    catch(...)
-      {
-       delete [] _M_caches;
-       __throw_exception_again;
-      }
-    for (size_t __i = 0; __i < _M_facets_size; ++__i)
-      {
-       _M_caches[__i] = __imp._M_caches[__i];
        if (_M_caches[__i])
-         _M_caches[__i]->_M_add_reference(); 
+         _M_caches[__i]->_M_add_reference();   
       }
 
-    try 
+    // Name all the categories.
+    for (size_t __i = 0; __i < _S_categories_size; ++__i)
+      _M_names[__i] = 0;
+    try
       {
-       _M_names = new char*[_S_categories_size];
+       for (size_t __i = 0; __i < _S_categories_size; ++__i)
+         {
+           char* __new = new char[std::strlen(__imp._M_names[__i]) + 1];
+           std::strcpy(__new, __imp._M_names[__i]);
+           _M_names[__i] = __new;
+         }
       }
     catch(...)
       {
-       delete [] _M_names;
+       this->~_Impl();
        __throw_exception_again;
       }
-    for (size_t __i = 0; __i < _S_categories_size; ++__i)
-      {
-       char* __new = new char[strlen(__imp._M_names[__i]) + 1];
-       std::strcpy(__new, __imp._M_names[__i]);
-       _M_names[__i] = __new;
-      }
   }
 
   // Construct named _Impl.
@@ -172,66 +165,61 @@ namespace std
     __c_locale __cloc;
     locale::facet::_S_create_c_locale(__cloc, __s);
 
+    _M_facets = _M_caches = 0;
+    _M_names = 0;
     try
-      { 
-       _M_facets = new const facet*[_M_facets_size]; 
-       for (size_t __i = 0; __i < _M_facets_size; ++__i)
-         _M_facets[__i] = 0;
-      }
-    catch(...) 
       {
-       delete [] _M_facets;
-       __throw_exception_again;
-      }
-
-    try 
-      {
-       _M_caches = new const facet*[_M_facets_size];
-       for (size_t __i = 0; __i < _M_facets_size; ++__i)
-         _M_caches[__i] = 0;
+       _M_facets = new const facet*[_M_facets_size];
+       _M_caches = new const facet*[_M_facets_size];
+       _M_names = new char*[_S_categories_size];
       }
     catch(...)
       {
+       delete [] _M_facets;
        delete [] _M_caches;
        __throw_exception_again;
-      }
+      }      
+
+    for (size_t __i = 0; __i < _M_facets_size; ++__i)
+      _M_facets[__i] = _M_caches[__i] = 0;
 
     // Name all the categories.
-    try 
-      {
-       _M_names = new char*[_S_categories_size];
-      }
-    catch(...)
-      {
-       delete [] _M_names;
-       __throw_exception_again;
-      }
-    size_t __len = std::strlen(__s);
-    if (!std::strchr(__s, ';'))
+    for (size_t __i = 0; __i < _S_categories_size; ++__i)
+      _M_names[__i] = 0;
+    try
       {
-       for (size_t __i = 0; __i < _S_categories_size; ++__i)
+       const size_t __len = std::strlen(__s);
+       if (!std::strchr(__s, ';'))
          {
-           _M_names[__i] = new char[__len + 1];
-           std::strcpy(_M_names[__i], __s);
+           for (size_t __i = 0; __i < _S_categories_size; ++__i)
+             {
+               _M_names[__i] = new char[__len + 1];
+               std::strcpy(_M_names[__i], __s);
+             }
          }
-      }
-    else
-      {
-       const char* __beg = __s;
-       for (size_t __i = 0; __i < _S_categories_size; ++__i)
+       else
          {
-           __beg = std::strchr(__beg, '=') + 1;
-           const char* __end = std::strchr(__beg, ';');
-           if (!__end)
-             __end = __s + __len;
-           char* __new = new char[__end - __beg + 1];
-           std::memcpy(__new, __beg, __end - __beg);
-           __new[__end - __beg] = '\0';
-           _M_names[__i] = __new;
+           const char* __beg = __s;
+           for (size_t __i = 0; __i < _S_categories_size; ++__i)
+             {
+               __beg = std::strchr(__beg, '=') + 1;
+               const char* __end = std::strchr(__beg, ';');
+               if (!__end)
+                 __end = __s + __len;
+               char* __new = new char[__end - __beg + 1];
+               std::memcpy(__new, __beg, __end - __beg);
+               __new[__end - __beg] = '\0';
+               _M_names[__i] = __new;
+             }
          }
       }
+    catch(...)
+      {
+       this->~_Impl();
+       __throw_exception_again;
+      }
 
-    // Construct all standard facets and add them to _M_facets.  
+    // Construct all standard facets and add them to _M_facets.
     _M_init_facet(new std::ctype<char>(__cloc, 0, false));
     _M_init_facet(new codecvt<char, char, mbstate_t>(__cloc));
     _M_init_facet(new numpunct<char>(__cloc));
@@ -263,6 +251,7 @@ namespace std
     _M_init_facet(new time_put<wchar_t>);
     _M_init_facet(new std::messages<wchar_t>(__cloc, __s));
 #endif   
+
     locale::facet::_S_destroy_c_locale(__cloc);
   }
 
@@ -278,19 +267,16 @@ namespace std
                                      locale::facet::_S_c_name);
 
     _M_facets = new (&facet_vec) const facet*[_M_facets_size];
-    for (size_t __i = 0; __i < _M_facets_size; ++__i)
-      _M_facets[__i] = 0;
-
     _M_caches = new (&cache_vec) const facet*[_M_facets_size];
     for (size_t __i = 0; __i < _M_facets_size; ++__i)
-      _M_caches[__i] = 0;
+      _M_facets[__i] = _M_caches[__i] = 0;
 
     // Name all the categories.
     _M_names = new (&name_vec) char*[_S_categories_size];
     for (size_t __i = 0; __i < _S_categories_size; ++__i)
       {
        _M_names[__i] = new (&name_c[__i]) char[2];
-       strcpy(_M_names[__i], locale::facet::_S_c_name);
+       std::strcpy(_M_names[__i], locale::facet::_S_c_name);
       }
 
     // This is needed as presently the C++ version of "C" locales
@@ -357,7 +343,7 @@ namespace std
     _M_init_facet(new (&time_put_w) time_put<wchar_t>(1));
     _M_init_facet(new (&messages_w) std::messages<wchar_t>(1));
 #endif 
-
+     
     // This locale is safe to pre-cache, after all the facets have
     // been created and installed.
     _M_caches[numpunct<char>::id._M_id()] = __npc;
@@ -388,9 +374,9 @@ namespace std
            if (std::strcmp(_M_names[__ix], "*") != 0 
                && std::strcmp(__imp->_M_names[__ix], "*") != 0)
              {
-               delete [] _M_names[__ix];
                char* __new = new char[std::strlen(__imp->_M_names[__ix]) + 1];
                std::strcpy(__new, __imp->_M_names[__ix]);
+               delete [] _M_names[__ix];
                _M_names[__ix] = __new;
              }
          }
@@ -440,7 +426,15 @@ namespace std
            // New cache array.
            const facet** __oldc = _M_caches;
            const facet** __newc;
-           __newc = new const facet*[__new_size]; 
+           try
+             {
+               __newc = new const facet*[__new_size];
+             }
+           catch(...)
+             {
+               delete [] __newf;
+               __throw_exception_again;
+             }
            for (size_t __i = 0; __i < _M_facets_size; ++__i)
              __newc[__i] = _M_caches[__i];
            for (size_t __i2 = _M_facets_size; __i2 < __new_size; ++__i2)
diff --git a/libstdc++-v3/testsuite/22_locale/locale/cons/12352.cc b/libstdc++-v3/testsuite/22_locale/locale/cons/12352.cc
new file mode 100644 (file)
index 0000000..4263959
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright (C) 2003 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.1.1.2 locale constructors and destructors [lib.locale.cons]
+
+#include <new>
+#include <locale>
+#include <cstdlib>
+#include <cstring>
+
+int times_to_fail = 0;
+
+void* allocate(std::size_t n)
+{
+  if (!times_to_fail--)
+    return 0;
+
+  void* ret = std::malloc(n ? n : 1);
+  if (ret)
+    std::memset(ret, 0xbc, n);
+  return ret;
+}
+
+void deallocate(void* p)
+{
+  if (p)
+    std::free(p);
+}
+
+void* operator new(std::size_t n) throw (std::bad_alloc)
+{
+  void* ret = allocate(n);
+  if (!ret)
+    throw std::bad_alloc();
+  return ret;
+}
+
+void* operator new[](std::size_t n) throw (std::bad_alloc)
+{
+  void* ret = allocate(n);
+  if (!ret)
+    throw std::bad_alloc();
+  return ret;
+}
+
+void operator delete(void* p) throw()
+{
+  deallocate(p);
+}
+
+void operator delete[](void* p) throw()
+{
+  deallocate(p);
+}
+
+void* operator new(std::size_t n, const std::nothrow_t&) throw()
+{
+  return allocate(n);
+}
+
+void* operator new[](std::size_t n, const std::nothrow_t&) throw()
+{
+  return allocate(n);
+}
+
+void operator delete(void* p, const std::nothrow_t&) throw()
+{
+  deallocate(p);
+}
+
+void operator delete[](void* p, const std::nothrow_t&) throw()
+{
+  deallocate(p);
+}
+
+// libstdc++/12352
+void test01(int iters)
+{
+  using namespace std;
+  bool test = true;
+
+  for (int j = 0; j < iters; ++j)
+    {
+      for (int i = 0; i < 100; ++i)
+       {
+         times_to_fail = i;
+         try
+           {
+             locale loc1("");
+             locale loc2(loc1, locale::classic(), locale::numeric);
+           }
+         catch (exception&)
+           {
+           }
+       }
+    }
+}
+
+int main(int argc, char* argv[])
+{
+  int iters = 1;
+  if (argc > 1)
+    iters = std::atoi(argv[1]);
+  if (iters < 1)
+    iters = 1;
+  test01(iters);
+
+  return 0;
+}