diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 2ac17ed9a45..7729b7bbd6b 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,23 @@ +2003-09-25 Paolo Carlini + + 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 PR libstdc++/6072 diff --git a/libstdc++-v3/include/bits/locale_classes.h b/libstdc++-v3/include/bits/locale_classes.h index b93cfb38142..49ece4ce1f5 100644 --- a/libstdc++-v3/include/bits/locale_classes.h +++ b/libstdc++-v3/include/bits/locale_classes.h @@ -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 { - delete [] _M_impl->_M_names[__i]; - char* __new = new char[2]; - std::strcpy(__new, "*"); - _M_impl->_M_names[__i] = __new; + 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[__k]; + _M_impl->_M_names[__k] = _M_tmp_names[__k]; } } } // namespace std diff --git a/libstdc++-v3/src/localename.cc b/libstdc++-v3/src/localename.cc index d428290b438..866e8979a65 100644 --- a/libstdc++-v3/src/localename.cc +++ b/libstdc++-v3/src/localename.cc @@ -44,7 +44,7 @@ namespace __gnu_cxx extern numpunct numpunct_c; extern num_get num_get_c; extern num_put num_put_c; -extern codecvt codecvt_c; + extern codecvt codecvt_c; extern moneypunct moneypunct_cf; extern moneypunct moneypunct_ct; extern money_get 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; + { + _M_facets = new const facet*[_M_facets_size]; + _M_caches = new const facet*[_M_facets_size]; + _M_names = new char*[_S_categories_size]; } - catch(...) + 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; - } - catch(...) - { 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 + for (size_t __i = 0; __i < _S_categories_size; ++__i) + _M_names[__i] = 0; + try { - _M_names = new char*[_S_categories_size]; + const size_t __len = std::strlen(__s); + if (!std::strchr(__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) + { + __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(...) { - delete [] _M_names; + this->~_Impl(); __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] = 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) - { - __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; - } - } - // 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(__cloc, 0, false)); _M_init_facet(new codecvt(__cloc)); _M_init_facet(new numpunct(__cloc)); @@ -263,6 +251,7 @@ namespace std _M_init_facet(new time_put); _M_init_facet(new std::messages(__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(1)); _M_init_facet(new (&messages_w) std::messages(1)); #endif - + // This locale is safe to pre-cache, after all the facets have // been created and installed. _M_caches[numpunct::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 index 00000000000..42639595154 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/locale/cons/12352.cc @@ -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 +#include +#include +#include + +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; +}