diff options
author | Eike Rathke <erack@redhat.com> | 2014-11-15 02:00:16 +0100 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2014-11-15 06:12:05 +0000 |
commit | 547d613e0868726e602ccb00fca0e7518a6c4bee (patch) | |
tree | 200143cddf42319e3a2c74f9d149ad0b2779264d | |
parent | 5839f0c4b98b37327a80b3fbe66d3b28459737b0 (diff) |
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>
-rw-r--r-- | sc/inc/chartlis.hxx | 6 | ||||
-rw-r--r-- | sc/source/core/tool/chartlis.cxx | 21 |
2 files changed, 27 insertions, 0 deletions
diff --git a/sc/inc/chartlis.hxx b/sc/inc/chartlis.hxx index 24c1bcdc0913..7feebf364067 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 4a96cf62aaf4..87cdb6ef7045 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() |