crashtesting: intermittent threaded crash

race in SwDoc::CreateNumberFormatter on thread unsafe mpNumberFormatter.

thread 1:
SwDoc::CreateNumberFormatter
SwDoc::GetNumberFormatter
...
sw::DocumentTimerManager::DoIdleJobs
Timer::Invoke

thread 2:
SwDoc::CreateNumberFormatter
SwDoc::GetNumberFormatter
SwXTextDocument::GetNumberFormatter();
SwXTextDocument::queryInterface
...
SvXMLExport::setSourceDocument
SvXMLNumFmtExport::SvXMLNumFmtExport

Change-Id: Iad9aa9514c9de61eb40256b954d0444d9fc9d81e
Reviewed-on: https://gerrit.libreoffice.org/65034
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index a12024f..30e3890 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -39,6 +39,7 @@
#include "tblenum.hxx"
#include "ndarr.hxx"
#include "ndtyp.hxx"
#include <atomic>
#include <memory>
#include <set>
#include <unordered_map>
@@ -258,7 +259,7 @@ class SW_DLLPUBLIC SwDoc final
    std::unique_ptr<SwAutoCorrExceptWord> mpACEWord;               /**< For the automated takeover of
                                                   auto-corrected words that are "re-corrected". */
    std::unique_ptr<SwURLStateChanged> mpURLStateChgd;             //< SfxClient for changes in INetHistory
    std::unique_ptr<SvNumberFormatter> mpNumberFormatter;          //< NumFormatter for tables / fields
    std::atomic<SvNumberFormatter*> mpNumberFormatter;             //< NumFormatter for tables / fields

    mutable std::unique_ptr<SwNumRuleTable> mpNumRuleTable;     //< List of all named NumRules.

@@ -347,7 +348,7 @@ private:
                                const OUString& rFormula,
                                std::vector<OUString>& rUsedDBNames );

    void CreateNumberFormatter();
    void EnsureNumberFormatter();

    bool UnProtectTableCells( SwTable& rTable );

@@ -1382,8 +1383,17 @@ public:
            SwRootFrame const* pLayout = nullptr);

    // Query NumberFormatter.
    inline       SvNumberFormatter* GetNumberFormatter( bool bCreate = true );
    inline const SvNumberFormatter* GetNumberFormatter( bool bCreate = true ) const;
    SvNumberFormatter* GetNumberFormatter(bool bCreate = true)
    {
        if (bCreate)
            EnsureNumberFormatter();
        return mpNumberFormatter;
    }

    const SvNumberFormatter* GetNumberFormatter(bool bCreate = true) const
    {
        return const_cast<SwDoc*>(this)->GetNumberFormatter(bCreate);
    }

    bool HasInvisibleContent() const;
    // delete invisible content, like hidden sections and paragraphs
@@ -1634,18 +1644,6 @@ inline const SwTableNode* SwDoc::IsIdxInTable( const SwNodeIndex& rIdx ) const
    return const_cast<SwDoc*>(this)->IsIdxInTable( rIdx );
}

inline SvNumberFormatter* SwDoc::GetNumberFormatter( bool bCreate )
{
    if( bCreate && !mpNumberFormatter )
        CreateNumberFormatter();
    return mpNumberFormatter.get();
}

inline const SvNumberFormatter* SwDoc::GetNumberFormatter( bool bCreate ) const
{
    return const_cast<SwDoc*>(this)->GetNumberFormatter( bCreate );
}

inline void SwDoc::SetOLEPrtNotifyPending( bool bSet )
{
    mbOLEPrtNotifyPending = bSet;
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index d29d731..8783623 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -30,6 +30,7 @@
#include <editeng/colritem.hxx>
#include <svl/whiter.hxx>
#include <svl/zforlist.hxx>
#include <comphelper/doublecheckedinit.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/configmgr.hxx>
#include <unotools/misccfg.hxx>
@@ -1731,16 +1732,17 @@ SwTableLineFormat* SwDoc::MakeTableLineFormat()
    return pFormat;
}

void SwDoc::CreateNumberFormatter()
void SwDoc::EnsureNumberFormatter()
{
    OSL_ENSURE( !mpNumberFormatter, "is already there" );

    LanguageType eLang = LANGUAGE_SYSTEM;

    mpNumberFormatter.reset( new SvNumberFormatter( comphelper::getProcessComponentContext(), eLang ) );
    mpNumberFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL );
    if (!utl::ConfigManager::IsFuzzing())
        mpNumberFormatter->SetYear2000(static_cast<sal_uInt16>(::utl::MiscCfg().GetYear2000()));
    comphelper::doubleCheckedInit(mpNumberFormatter, []()
    {
        LanguageType eLang = LANGUAGE_SYSTEM;
        SvNumberFormatter* pRet = new SvNumberFormatter(comphelper::getProcessComponentContext(), eLang);
        pRet->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL );
        if (!utl::ConfigManager::IsFuzzing())
            pRet->SetYear2000(static_cast<sal_uInt16>(::utl::MiscCfg().GetYear2000()));
        return pRet;
    });
}

SwTableNumFormatMerge::SwTableNumFormatMerge( const SwDoc& rSrc, SwDoc& rDest )
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index bc36cbc..a1034a6 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -252,6 +252,7 @@ SwDoc::SwDoc()
    mpLineNumberInfo( new SwLineNumberInfo ),
    mpFootnoteIdxs( new SwFootnoteIdxs ),
    mpDocShell( nullptr ),
    mpNumberFormatter( nullptr ),
    mpNumRuleTable( new SwNumRuleTable ),
    mpExtInputRing( nullptr ),
    mpGrammarContact(createGrammarContact()),
@@ -579,7 +580,7 @@ SwDoc::~SwDoc()

    disposeXForms(); // #i113606#, dispose the XForms objects

    mpNumberFormatter.reset();
    delete mpNumberFormatter.load(); mpNumberFormatter= nullptr;
    mpFootnoteInfo.reset();
    mpEndNoteInfo.reset();
    mpLineNumberInfo.reset();
@@ -736,7 +737,7 @@ void SwDoc::ClearDoc()

    GetDocumentFieldsManager().ClearFieldTypes();

    mpNumberFormatter.reset();
    delete mpNumberFormatter.load(); mpNumberFormatter= nullptr;

    getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD );
    pFirstNd->ChgFormatColl( getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ));