diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2021-08-02 15:41:53 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2021-08-02 17:09:49 +0200 |
commit | 71d0c43fb4cf535239cb41baf7b6e03de765ce7a (patch) | |
tree | 09a931cc275ae9563bfde9fdec589574b2e121fc /i18nlangtag | |
parent | 0f3497ea6080df72d479a405886316da21e35885 (diff) |
initialization-order-fiasco
...after a943936eeff04b60ebd0b2552bc18b42606f3321 "rtl::Static -> static local"
(and the relevant static isn't even local), when building e.g.
Gallery/backgrounds, see <https://ci.libreoffice.org/job/lo_ubsan/2090/>:
> ==26993==ERROR: AddressSanitizer: initialization-order-fiasco on address 0x2b52e50be408 at pc 0x2b52e4d32753 bp 0x7fff5670f090 sp 0x7fff5670f088
> READ of size 8 at 0x2b52e50be408 thread T0
> #0 0x2b52e4d32752 in std::_Rb_tree<rtl::OUString, std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> >, std::_Select1st<std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> > >, (anonymous namespace)::compareIgnoreAsciiCaseLess, std::allocator<std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> > > >::_M_begin() /home/tdf/lode/opt_private/gcc-7.3.0/lib/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_tree.h:737:64
> #1 0x2b52e4d355f3 in std::_Rb_tree<rtl::OUString, std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> >, std::_Select1st<std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> > >, (anonymous namespace)::compareIgnoreAsciiCaseLess, std::allocator<std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> > > >::find(rtl::OUString const&) /home/tdf/lode/opt_private/gcc-7.3.0/lib/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_tree.h:2523:37
> #2 0x2b52e4d3507d in std::__cxx1998::map<rtl::OUString, std::shared_ptr<LanguageTagImpl>, (anonymous namespace)::compareIgnoreAsciiCaseLess, std::allocator<std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> > > >::find(rtl::OUString const&) /home/tdf/lode/opt_private/gcc-7.3.0/lib/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/bits/stl_map.h:1164:21
> #3 0x2b52e4cf116c in std::__debug::map<rtl::OUString, std::shared_ptr<LanguageTagImpl>, (anonymous namespace)::compareIgnoreAsciiCaseLess, std::allocator<std::pair<rtl::OUString const, std::shared_ptr<LanguageTagImpl> > > >::find(rtl::OUString const&) /home/tdf/lode/opt_private/gcc-7.3.0/lib/gcc/x86_64-pc-linux-gnu/7.3.0/../../../../include/c++/7.3.0/debug/map.h:561:32
> #4 0x2b52e4d00dcd in LanguageTag::registerImpl() const /i18nlangtag/source/languagetag/languagetag.cxx:888:50
> #5 0x2b52e4cdf693 in LanguageTag::getImpl() /i18nlangtag/source/languagetag/languagetag.cxx:1004:18
> #6 0x2b52e4cdf3fd in LanguageTag::LanguageTag(rtl::OUString const&, bool) /i18nlangtag/source/languagetag/languagetag.cxx:489:9
> #7 0x2b52b9aed628 in __cxx_global_var_init.2 /sfx2/source/view/lokhelper.cxx:77:13
> #8 0x2b52b9aed75e in _GLOBAL__sub_I_lokhelper.cxx /sfx2/source/view/lokhelper.cxx
> #9 0x2b52b4f069c2 in _dl_init_internal (/lib64/ld-linux-x86-64.so.2+0xf9c2)
> #10 0x2b52b4ef8179 (/lib64/ld-linux-x86-64.so.2+0x1179)
>
> 0x2b52e50be408 is located 40 bytes inside of global variable '(anonymous namespace)::theMapBcp47' defined in '/home/tdf/lode/jenkins/workspace/lo_ubsan/i18nlangtag/source/languagetag/languagetag.cxx:93:10' (0x2b52e50be3e0) of size 72
> registered at:
> #0 0x43f4c8 in __asan_register_globals.part.13 /home/tdf/lode/packages/llvm-llvmorg-9.0.1.src/compiler-rt/lib/asan/asan_globals.cc:362
> #1 0x2b52e4d4031b in asan.module_ctor (/instdir/program/libi18nlangtag.so+0x16831b)
> LLVMSymbolizer: error reading file: No such file or directory
> #2 0x7fff567143b7 ([stack]+0x203b7)
This is a partial revert of a943936eeff04b60ebd0b2552bc18b42606f3321
"rtl::Static -> static local".
Change-Id: I5d6803d217d4e8927b5864b2392f3ddd18310a5a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119882
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'i18nlangtag')
-rw-r--r-- | i18nlangtag/source/languagetag/languagetag.cxx | 89 |
1 files changed, 48 insertions, 41 deletions
diff --git a/i18nlangtag/source/languagetag/languagetag.cxx b/i18nlangtag/source/languagetag/languagetag.cxx index 07b9c6d0a666..41f23973020f 100644 --- a/i18nlangtag/source/languagetag/languagetag.cxx +++ b/i18nlangtag/source/languagetag/languagetag.cxx @@ -49,19 +49,24 @@ struct myLtError ~myLtError() { if (p) lt_error_unref( p); } }; +// "static" to be returned as const reference to an empty locale. +struct theEmptyLocale : public rtl::Static< lang::Locale, theEmptyLocale > {}; } typedef std::unordered_set< OUString > KnownTagSet; namespace { +struct theKnowns : public rtl::Static< KnownTagSet, theKnowns > {}; struct theMutex : public rtl::Static< osl::Mutex, theMutex > {}; } static const KnownTagSet & getKnowns() { - static const KnownTagSet theKnowns = - []() + KnownTagSet & rKnowns = theKnowns::get(); + if (rKnowns.empty()) + { + osl::MutexGuard aGuard( theMutex::get()); + if (rKnowns.empty()) { - KnownTagSet knownSet; ::std::vector< MsLangId::LanguagetagMapping > aDefined( MsLangId::getDefinedLanguagetags()); for (auto const& elemDefined : aDefined) { @@ -71,12 +76,12 @@ static const KnownTagSet & getKnowns() ::std::vector< OUString > aFallbacks( LanguageTag( elemDefined.mnLang).getFallbackStrings( true)); for (auto const& fallback : aFallbacks) { - knownSet.insert(fallback); + rKnowns.insert(fallback); } } - return knownSet; - }(); - return theKnowns; + } + } + return rKnowns; } @@ -90,10 +95,10 @@ struct compareIgnoreAsciiCaseLess }; typedef ::std::map< OUString, LanguageTag::ImplPtr, compareIgnoreAsciiCaseLess > MapBcp47; typedef ::std::map< LanguageType, LanguageTag::ImplPtr > MapLangID; -MapBcp47 theMapBcp47; -MapLangID theMapLangID; -LanguageTag::ImplPtr theDontKnow; -LanguageTag::ImplPtr theSystemLocale; +struct theMapBcp47 : public rtl::Static< MapBcp47, theMapBcp47 > {}; +struct theMapLangID : public rtl::Static< MapLangID, theMapLangID > {}; +struct theDontKnow : public rtl::Static< LanguageTag::ImplPtr, theDontKnow > {}; +struct theSystemLocale : public rtl::Static< LanguageTag::ImplPtr, theSystemLocale > {}; } @@ -593,9 +598,10 @@ LanguageTag::ImplPtr LanguageTagImpl::registerOnTheFly( LanguageType nRegisterID osl::MutexGuard aGuard( theMutex::get()); - MapBcp47::const_iterator it( theMapBcp47.find( maBcp47)); + MapBcp47& rMapBcp47 = theMapBcp47::get(); + MapBcp47::const_iterator it( rMapBcp47.find( maBcp47)); bool bOtherImpl = false; - if (it != theMapBcp47.end()) + if (it != rMapBcp47.end()) { SAL_INFO( "i18nlangtag", "LanguageTag::registerOnTheFly: found impl for '" << maBcp47 << "'"); pImpl = (*it).second; @@ -615,7 +621,7 @@ LanguageTag::ImplPtr LanguageTagImpl::registerOnTheFly( LanguageType nRegisterID { SAL_INFO( "i18nlangtag", "LanguageTag::registerOnTheFly: new impl for '" << maBcp47 << "'"); pImpl = std::make_shared<LanguageTagImpl>( *this); - theMapBcp47.insert( ::std::make_pair( maBcp47, pImpl)); + rMapBcp47.insert( ::std::make_pair( maBcp47, pImpl)); } if (!bOtherImpl || !pImpl->mbInitializedLangID) @@ -628,8 +634,9 @@ LanguageTag::ImplPtr LanguageTagImpl::registerOnTheFly( LanguageType nRegisterID // different, otherwise we would end up with ambiguous assignments // of different language tags, for example for the same primary // LangID with "no", "nb" and "nn". - MapLangID::const_iterator itID( theMapLangID.find( nRegisterID)); - if (itID != theMapLangID.end()) + const MapLangID& rMapLangID = theMapLangID::get(); + MapLangID::const_iterator itID( rMapLangID.find( nRegisterID)); + if (itID != rMapLangID.end()) { if ((*itID).second->maBcp47 != maBcp47) { @@ -660,7 +667,7 @@ LanguageTag::ImplPtr LanguageTagImpl::registerOnTheFly( LanguageType nRegisterID } ::std::pair< MapLangID::const_iterator, bool > res( - theMapLangID.insert( ::std::make_pair( pImpl->mnLangID, pImpl))); + theMapLangID::get().insert( ::std::make_pair( pImpl->mnLangID, pImpl))); if (res.second) { SAL_INFO( "i18nlangtag", "LanguageTag::registerOnTheFly: cross-inserted 0x" @@ -679,8 +686,9 @@ LanguageTag::ImplPtr LanguageTagImpl::registerOnTheFly( LanguageType nRegisterID LanguageTag::ScriptType LanguageTag::getOnTheFlyScriptType( LanguageType nRegisterID ) { - MapLangID::const_iterator itID( theMapLangID.find( nRegisterID)); - if (itID != theMapLangID.end()) + const MapLangID& rMapLangID = theMapLangID::get(); + MapLangID::const_iterator itID( rMapLangID.find( nRegisterID)); + if (itID != rMapLangID.end()) return (*itID).second->getScriptType(); else return ScriptType::UNKNOWN; @@ -701,7 +709,7 @@ void LanguageTag::setConfiguredSystemLanguage( LanguageType nLang ) MsLangId::LanguageTagAccess::setConfiguredSystemLanguage( nLang); // Reset system locale to none and let registerImpl() do the rest to // initialize a new one. - theSystemLocale.reset(); + theSystemLocale::get().reset(); LanguageTag aLanguageTag( LANGUAGE_SYSTEM); aLanguageTag.registerImpl(); } @@ -741,7 +749,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const // and take the system locale shortcut if possible. if (mbSystemLocale) { - pImpl = theSystemLocale; + pImpl = theSystemLocale::get(); if (pImpl) { #if OSL_DEBUG_LEVEL > 0 @@ -766,9 +774,10 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const // Heavy usage of LANGUAGE_DONTKNOW, make it an own Impl for all the // conversion attempts. At the same time provide a central breakpoint // to inspect such places. - if (!theDontKnow) - theDontKnow = std::make_shared<LanguageTagImpl>( *this); - pImpl = theDontKnow; + LanguageTag::ImplPtr& rDontKnow = theDontKnow::get(); + if (!rDontKnow) + rDontKnow = std::make_shared<LanguageTagImpl>( *this); + pImpl = rDontKnow; #if OSL_DEBUG_LEVEL > 0 static size_t nCallsDontKnow = 0; ++nCallsDontKnow; @@ -779,7 +788,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const else { // A great share are calls for a system equal locale. - pImpl = theSystemLocale; + pImpl = theSystemLocale::get(); if (pImpl && pImpl->mnLangID == mnLangID) { #if OSL_DEBUG_LEVEL > 0 @@ -810,7 +819,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const if (mbInitializedBcp47) { // A great share are calls for a system equal locale. - pImpl = theSystemLocale; + pImpl = theSystemLocale::get(); if (pImpl && pImpl->maBcp47 == maBcp47) { #if OSL_DEBUG_LEVEL > 0 @@ -843,8 +852,9 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const // Prefer LangID map as find+insert needs less comparison work. if (mbInitializedLangID) { - MapLangID::const_iterator it( theMapLangID.find( mnLangID)); - if (it != theMapLangID.end()) + MapLangID& rMap = theMapLangID::get(); + MapLangID::const_iterator it( rMap.find( mnLangID)); + if (it != rMap.end()) { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: found impl for 0x" << ::std::hex << mnLangID); pImpl = (*it).second; @@ -853,7 +863,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: new impl for 0x" << ::std::hex << mnLangID); pImpl = std::make_shared<LanguageTagImpl>( *this); - theMapLangID.insert( ::std::make_pair( mnLangID, pImpl)); + rMap.insert( ::std::make_pair( mnLangID, pImpl)); // Try round-trip. if (!pImpl->mbInitializedLocale) pImpl->convertLangToLocale(); @@ -864,7 +874,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const if (!pImpl->mbInitializedBcp47) pImpl->convertLocaleToBcp47(); ::std::pair< MapBcp47::const_iterator, bool > res( - theMapBcp47.insert( ::std::make_pair( pImpl->maBcp47, pImpl))); + theMapBcp47::get().insert( ::std::make_pair( pImpl->maBcp47, pImpl))); if (res.second) { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: cross-inserted '" << pImpl->maBcp47 << "' for 0x" << ::std::hex << mnLangID); @@ -885,8 +895,9 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const } else if (!maBcp47.isEmpty()) { - MapBcp47::const_iterator it( theMapBcp47.find( maBcp47)); - if (it != theMapBcp47.end()) + MapBcp47& rMap = theMapBcp47::get(); + MapBcp47::const_iterator it( rMap.find( maBcp47)); + if (it != rMap.end()) { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: found impl for '" << maBcp47 << "'"); pImpl = (*it).second; @@ -895,14 +906,14 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: new impl for '" << maBcp47 << "'"); pImpl = std::make_shared<LanguageTagImpl>( *this); - ::std::pair< MapBcp47::iterator, bool > insOrig( theMapBcp47.insert( ::std::make_pair( maBcp47, pImpl))); + ::std::pair< MapBcp47::iterator, bool > insOrig( rMap.insert( ::std::make_pair( maBcp47, pImpl))); // If changed after canonicalize() also add the resulting tag to // the map. if (pImpl->synCanonicalize()) { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: canonicalized to '" << pImpl->maBcp47 << "'"); ::std::pair< MapBcp47::const_iterator, bool > insCanon( - theMapBcp47.insert( ::std::make_pair( pImpl->maBcp47, pImpl))); + rMap.insert( ::std::make_pair( pImpl->maBcp47, pImpl))); SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: " << (insCanon.second ? "" : "not ") << "inserted '" << pImpl->maBcp47 << "'"); // If the canonicalized tag already existed (was not inserted) @@ -946,7 +957,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const if (bInsert) { ::std::pair< MapLangID::const_iterator, bool > res( - theMapLangID.insert( ::std::make_pair( pImpl->mnLangID, pImpl))); + theMapLangID::get().insert( ::std::make_pair( pImpl->mnLangID, pImpl))); if (res.second) { SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: cross-inserted 0x" @@ -978,7 +989,7 @@ LanguageTag::ImplPtr LanguageTag::registerImpl() const // above, so add it. if (mbSystemLocale && mbInitializedLangID) { - theSystemLocale = pImpl; + theSystemLocale::get() = pImpl; SAL_INFO( "i18nlangtag", "LanguageTag::registerImpl: added system locale 0x" << ::std::hex << pImpl->mnLangID << " '" << pImpl->maBcp47 << "'"); } @@ -1688,11 +1699,7 @@ OUString LanguageTagImpl::getVariantsFromLangtag() const css::lang::Locale & LanguageTag::getLocale( bool bResolveSystem ) const { if (!bResolveSystem && mbSystemLocale) - { - // "static" to be returned as const reference to an empty locale. - static const lang::Locale theEmptyLocale; - return theEmptyLocale; - } + return theEmptyLocale::get(); if (!mbInitializedLocale) syncVarsFromImpl(); if (!mbInitializedLocale) |