From c8036448d18101ce03661a2e6179d07b6178b6fb Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Tue, 19 May 2009 18:20:47 +0000 Subject: [PATCH] re PR libstdc++/40184 (locale(const char* std_name) can create invalid facets for nonuniform locale) 2009-05-19 Paolo Carlini PR libstdc++/40184 * include/bits/locale_classes.h (locale::facet::_S_lc_ctype_c_locale): Declare... * config/locale/gnu/c_locale.cc: ... and define. * config/locale/generic/c_locale.cc: Define. * src/localename.cc (locale::_Impl::_Impl(const char*, size_t)): Use it. * testsuite/22_locale/locale/cons/40184.cc: New. From-SVN: r147714 --- libstdc++-v3/ChangeLog | 11 ++++ .../config/locale/generic/c_locale.cc | 4 ++ libstdc++-v3/config/locale/gnu/c_locale.cc | 21 ++++++- libstdc++-v3/include/bits/locale_classes.h | 3 + libstdc++-v3/src/localename.cc | 37 ++++++++++-- .../testsuite/22_locale/locale/cons/40184.cc | 60 +++++++++++++++++++ 6 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 libstdc++-v3/testsuite/22_locale/locale/cons/40184.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index ab3c32df63c..03a1397f624 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,14 @@ +2009-05-19 Paolo Carlini + + PR libstdc++/40184 + * include/bits/locale_classes.h (locale::facet::_S_lc_ctype_c_locale): + Declare... + * config/locale/gnu/c_locale.cc: ... and define. + * config/locale/generic/c_locale.cc: Define. + * src/localename.cc (locale::_Impl::_Impl(const char*, size_t)): + Use it. + * testsuite/22_locale/locale/cons/40184.cc: New. + 2009-05-18 Paolo Carlini PR libstdc++/40192 diff --git a/libstdc++-v3/config/locale/generic/c_locale.cc b/libstdc++-v3/config/locale/generic/c_locale.cc index 3b9f1bd42a5..a79a970f231 100644 --- a/libstdc++-v3/config/locale/generic/c_locale.cc +++ b/libstdc++-v3/config/locale/generic/c_locale.cc @@ -226,6 +226,10 @@ _GLIBCXX_BEGIN_NAMESPACE(std) locale::facet::_S_clone_c_locale(__c_locale&) { return __c_locale(); } + __c_locale + locale::facet::_S_lc_ctype_c_locale(__c_locale, const char*) + { return __c_locale(); } + _GLIBCXX_END_NAMESPACE _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) diff --git a/libstdc++-v3/config/locale/gnu/c_locale.cc b/libstdc++-v3/config/locale/gnu/c_locale.cc index cd32dc03130..4864d25cd34 100644 --- a/libstdc++-v3/config/locale/gnu/c_locale.cc +++ b/libstdc++-v3/config/locale/gnu/c_locale.cc @@ -133,10 +133,10 @@ _GLIBCXX_BEGIN_NAMESPACE(std) { // This named locale is not supported by the underlying OS. __throw_runtime_error(__N("locale::facet::_S_create_c_locale " - "name not valid")); + "name not valid")); } } - + void locale::facet::_S_destroy_c_locale(__c_locale& __cloc) { @@ -148,6 +148,23 @@ _GLIBCXX_BEGIN_NAMESPACE(std) locale::facet::_S_clone_c_locale(__c_locale& __cloc) { return __duplocale(__cloc); } + __c_locale + locale::facet::_S_lc_ctype_c_locale(__c_locale __cloc, const char* __s) + { + __c_locale __dup = __duplocale(__cloc); + if (__dup == __c_locale(0)) + __throw_runtime_error(__N("locale::facet::_S_lc_ctype_c_locale " + "duplocale error")); + __c_locale __changed = __newlocale(LC_CTYPE_MASK, __s, __dup); + if (__changed == __c_locale(0)) + { + __freelocale(__dup); + __throw_runtime_error(__N("locale::facet::_S_lc_ctype_c_locale " + "newlocale error")); + } + return __changed; + } + _GLIBCXX_END_NAMESPACE _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) diff --git a/libstdc++-v3/include/bits/locale_classes.h b/libstdc++-v3/include/bits/locale_classes.h index 1a7f2c20912..7ae9c53bc6a 100644 --- a/libstdc++-v3/include/bits/locale_classes.h +++ b/libstdc++-v3/include/bits/locale_classes.h @@ -381,6 +381,9 @@ _GLIBCXX_BEGIN_NAMESPACE(std) static void _S_destroy_c_locale(__c_locale& __cloc); + static __c_locale + _S_lc_ctype_c_locale(__c_locale __cloc, const char* __s); + // Returns data from the underlying "C" library data for the // classic locale. static __c_locale diff --git a/libstdc++-v3/src/localename.cc b/libstdc++-v3/src/localename.cc index ae932a3a7e0..98f6020533c 100644 --- a/libstdc++-v3/src/localename.cc +++ b/libstdc++-v3/src/localename.cc @@ -180,6 +180,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) // see if the given name is valid. __c_locale __cloc; locale::facet::_S_create_c_locale(__cloc, __s); + __c_locale __clocm = __cloc; __try { @@ -194,15 +195,19 @@ _GLIBCXX_BEGIN_NAMESPACE(std) _M_names[__k] = 0; // Name the categories. + const char* __smon = __s; const size_t __len = std::strlen(__s); if (!std::memchr(__s, ';', __len)) { _M_names[0] = new char[__len + 1]; - std::memcpy(_M_names[0], __s, __len + 1); + std::memcpy(_M_names[0], __s, __len + 1); } else { const char* __end = __s; + bool __found_ctype = false; + bool __found_monetary = false; + size_t __ci = 0, __mi = 0; for (size_t __i = 0; __i < _S_categories_size; ++__i) { const char* __beg = std::strchr(__end + 1, '=') + 1; @@ -212,6 +217,24 @@ _GLIBCXX_BEGIN_NAMESPACE(std) _M_names[__i] = new char[__end - __beg + 1]; std::memcpy(_M_names[__i], __beg, __end - __beg); _M_names[__i][__end - __beg] = '\0'; + if (!__found_ctype + && *(__beg - 2) == 'E' && *(__beg - 3) == 'P') + { + __found_ctype = true; + __ci = __i; + } + else if (!__found_monetary && *(__beg - 2) == 'Y') + { + __found_monetary = true; + __mi = __i; + } + } + + if (std::strcmp(_M_names[__ci], _M_names[__mi])) + { + __smon = _M_names[__mi]; + __clocm = locale::facet::_S_lc_ctype_c_locale(__cloc, + __smon); } } @@ -222,8 +245,8 @@ _GLIBCXX_BEGIN_NAMESPACE(std) _M_init_facet(new num_get); _M_init_facet(new num_put); _M_init_facet(new std::collate(__cloc)); - _M_init_facet(new moneypunct(__cloc, __s)); - _M_init_facet(new moneypunct(__cloc, __s)); + _M_init_facet(new moneypunct(__cloc, 0)); + _M_init_facet(new moneypunct(__cloc, 0)); _M_init_facet(new money_get); _M_init_facet(new money_put); _M_init_facet(new __timepunct(__cloc, __s)); @@ -238,8 +261,8 @@ _GLIBCXX_BEGIN_NAMESPACE(std) _M_init_facet(new num_get); _M_init_facet(new num_put); _M_init_facet(new std::collate(__cloc)); - _M_init_facet(new moneypunct(__cloc, __s)); - _M_init_facet(new moneypunct(__cloc, __s)); + _M_init_facet(new moneypunct(__clocm, __smon)); + _M_init_facet(new moneypunct(__clocm, __smon)); _M_init_facet(new money_get); _M_init_facet(new money_put); _M_init_facet(new __timepunct(__cloc, __s)); @@ -248,10 +271,14 @@ _GLIBCXX_BEGIN_NAMESPACE(std) _M_init_facet(new std::messages(__cloc, __s)); #endif locale::facet::_S_destroy_c_locale(__cloc); + if (__clocm != __cloc) + locale::facet::_S_destroy_c_locale(__clocm); } __catch(...) { locale::facet::_S_destroy_c_locale(__cloc); + if (__clocm != __cloc) + locale::facet::_S_destroy_c_locale(__clocm); this->~_Impl(); __throw_exception_again; } diff --git a/libstdc++-v3/testsuite/22_locale/locale/cons/40184.cc b/libstdc++-v3/testsuite/22_locale/locale/cons/40184.cc new file mode 100644 index 00000000000..d7e30eba1c3 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/locale/cons/40184.cc @@ -0,0 +1,60 @@ +// { dg-require-namedlocale "" } + +// Copyright (C) 2009 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 3, 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 COPYING3. If not see +// . + +// 22.1.1.2 locale constructors and destructors [lib.locale.cons] + +#include +#include + +// libstdc++/40184 +void test01() +{ +#ifdef _GLIBCXX_USE_WCHAR_T + using namespace std; + bool test __attribute__((unused)) = true; + + locale locf(locale("C"), "ja_JP.eucjp", locale::monetary); + + const moneypunct& mpf = + use_facet >(locf); + + locale locf_copy(locf.name().c_str()); + const moneypunct& mpf_copy = + use_facet >(locf_copy); + + VERIFY( mpf.curr_symbol() == mpf_copy.curr_symbol() ); + + locale loct(locale("C"), "ja_JP.eucjp", locale::monetary); + + const moneypunct& mpt = + use_facet >(loct); + + locale loct_copy(loct.name().c_str()); + const moneypunct& mpt_copy = + use_facet >(loct_copy); + + VERIFY( mpt.curr_symbol() == mpt_copy.curr_symbol() ); +#endif +} + +int main() +{ + test01(); + return 0; +} -- 2.30.2