From dfda2730a11e165f081dacbb4b5c30da3db07070 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Wed, 30 May 2018 09:00:20 +0200 Subject: protect one-time creation in ScGlobal::Get(Case)Collator() by a mutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise there is a race condition when calc uses threading, and lp#390983-2 sometimes crashes. Change-Id: I390928c02b8e7d74bebef2dcc98a5c21cb3a8197 Reviewed-on: https://gerrit.libreoffice.org/54795 Reviewed-by: Michael Meeks Tested-by: Luboš Luňák --- sc/source/core/data/global.cxx | 53 ++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) (limited to 'sc') diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx index 9e4ce14e3ddf..4ab08a7bc1bd 100644 --- a/sc/source/core/data/global.cxx +++ b/sc/source/core/data/global.cxx @@ -125,6 +125,33 @@ SfxViewShell* pScActiveViewShell = nullptr; //FIXME: Make this a member sal_uInt16 nScClickMouseModifier = 0; //FIXME: This too sal_uInt16 nScFillModeMouseModifier = 0; //FIXME: And this +// Thread-safe singleton creation. Ideally rtl_Instance should be used, but that one doesn't +// allow accessing the pointer (so ScGlobal::Clear() cannot free the objects). So this function +// is basically rtl_Instance::create() that uses a given pointer. +template< typename Type, typename Function = std::function< Type*() >, + typename Guard = osl::MutexGuard, typename GuardCtor = osl::GetGlobalMutex > +static inline +Type* doubleCheckedInit( Type* pointer, Function function, GuardCtor guardCtor = osl::GetGlobalMutex()) +{ + Type* p = pointer; + if (!p) + { + Guard guard(guardCtor()); + p = pointer; + if (!p) + { + p = function(); + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + pointer = p; + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + return p; +} + // Static functions bool ScGlobal::HasAttrChanged( const SfxItemSet& rNewAttrs, @@ -996,21 +1023,23 @@ CalendarWrapper* ScGlobal::GetCalendar() } CollatorWrapper* ScGlobal::GetCollator() { - if ( !pCollator ) - { - pCollator = new CollatorWrapper( ::comphelper::getProcessComponentContext() ); - pCollator->loadDefaultCollator( *GetLocale(), SC_COLLATOR_IGNORES ); - } - return pCollator; + return doubleCheckedInit( pCollator, + []() + { + CollatorWrapper* p = new CollatorWrapper( ::comphelper::getProcessComponentContext() ); + p->loadDefaultCollator( *GetLocale(), SC_COLLATOR_IGNORES ); + return p; + }); } CollatorWrapper* ScGlobal::GetCaseCollator() { - if ( !pCaseCollator ) - { - pCaseCollator = new CollatorWrapper( ::comphelper::getProcessComponentContext() ); - pCaseCollator->loadDefaultCollator( *GetLocale(), 0 ); - } - return pCaseCollator; + return doubleCheckedInit( pCaseCollator, + []() + { + CollatorWrapper* p = new CollatorWrapper( ::comphelper::getProcessComponentContext() ); + p->loadDefaultCollator( *GetLocale(), 0 ); + return p; + }); } ::utl::TransliterationWrapper* ScGlobal::GetCaseTransliteration() { -- cgit