fdo#73695 prevent use of invalidated iterator due to re-entrance

... through the UNO backdoor..
While charts are updated there can be chart data listeners in BASIC that
in turn modify things such that charts are inserted/removed from the
listener chain, invalidating the iterator. If that happens break and
bail out instead of crashing. Not ideal, but..

Change-Id: Iefb33d3a96d79caed0ee4e19b73e8f811ef3d937
(cherry picked from commit ef2ed50231fd946c1f374ffbce28ebb98eda56c5)
Reviewed-on: https://gerrit.libreoffice.org/12434
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
Tested-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
diff --git a/sc/inc/chartlis.hxx b/sc/inc/chartlis.hxx
index 24c1bcd..7feebf3 100644
--- a/sc/inc/chartlis.hxx
+++ b/sc/inc/chartlis.hxx
@@ -141,6 +141,12 @@ public:
    typedef boost::unordered_set<OUString, OUStringHash> StringSetType;
private:
    ListenersType maListeners;
    enum UpdateStatus
    {
        SC_CLCUPDATE_NONE,
        SC_CLCUPDATE_RUNNING,
        SC_CLCUPDATE_MODIFIED
    } meModifiedDuringUpdate;
    ::std::list<RangeListenerItem> maHiddenListeners;
    StringSetType maNonOleObjectNames;

diff --git a/sc/source/core/tool/chartlis.cxx b/sc/source/core/tool/chartlis.cxx
index 4a96cf6..87cdb6ef 100644
--- a/sc/source/core/tool/chartlis.cxx
+++ b/sc/source/core/tool/chartlis.cxx
@@ -421,6 +421,7 @@ ScChartListenerCollection::RangeListenerItem::RangeListenerItem(const ScRange& r
}

ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) :
    meModifiedDuringUpdate( SC_CLCUPDATE_NONE ),
    pDoc( pDocP )
{
    aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
@@ -428,6 +429,7 @@ ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) :

ScChartListenerCollection::ScChartListenerCollection(
        const ScChartListenerCollection& rColl ) :
    meModifiedDuringUpdate( SC_CLCUPDATE_NONE ),
    pDoc( rColl.pDoc )
{
    aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
@@ -451,12 +453,16 @@ void ScChartListenerCollection::StartAllListeners()

void ScChartListenerCollection::insert(ScChartListener* pListener)
{
    if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
        meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;
    OUString aName = pListener->GetName();
    maListeners.insert(aName, pListener);
}

void ScChartListenerCollection::removeByName(const OUString& rName)
{
    if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
        meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;
    maListeners.erase(rName);
}

@@ -544,6 +550,9 @@ public:

void ScChartListenerCollection::FreeUnused()
{
    if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
        meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;

    ListenersType aUsed, aUnused;

    // First, filter each listener into 'used' and 'unused' categories.
@@ -575,6 +584,9 @@ void ScChartListenerCollection::FreeUnused()
void ScChartListenerCollection::FreeUno( const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
                                         const uno::Reference< chart::XChartData >& rSource )
{
    if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
        meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;

    std::vector<ScChartListener*> aUsed, aUnused;

    // First, filter each listener into 'used' and 'unused' categories.
@@ -619,6 +631,11 @@ IMPL_LINK_NOARG(ScChartListenerCollection, TimerHdl)

void ScChartListenerCollection::UpdateDirtyCharts()
{
    // During ScChartListener::Update() the most nasty things can happen due to
    // UNO listeners, e.g. reentrant calls via BASIC to insert() and FreeUno()
    // and similar that modify maListeners and invalidate iterators.
    meModifiedDuringUpdate = SC_CLCUPDATE_RUNNING;

    ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
    for (; it != itEnd; ++it)
    {
@@ -626,9 +643,13 @@ void ScChartListenerCollection::UpdateDirtyCharts()
        if (p->IsDirty())
            p->Update();

        if (meModifiedDuringUpdate == SC_CLCUPDATE_MODIFIED)
            break;      // iterator is invalid

        if (aTimer.IsActive() && !pDoc->IsImportingXML())
            break;                      // one interfered
    }
    meModifiedDuringUpdate = SC_CLCUPDATE_NONE;
}

void ScChartListenerCollection::SetDirty()