diff options
author | Eike Rathke <erack@redhat.com> | 2014-11-15 02:00:16 +0100 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2014-11-15 02:08:34 +0100 |
commit | ef2ed50231fd946c1f374ffbce28ebb98eda56c5 (patch) | |
tree | c50e88c7d655bdd3969857cfa1dbe080c900ae89 | |
parent | 0b3766645d7d52d5c2022b1e8e4617eff06403c8 (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
-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 f9a364181389..9952d4bc6a03 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 be5632533959..837dbfecd1ab 100644 --- a/sc/source/core/tool/chartlis.cxx +++ b/sc/source/core/tool/chartlis.cxx @@ -411,6 +411,7 @@ ScChartListenerCollection::RangeListenerItem::RangeListenerItem(const ScRange& r } ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) : + meModifiedDuringUpdate( SC_CLCUPDATE_NONE ), pDoc( pDocP ) { aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) ); @@ -418,6 +419,7 @@ ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) : ScChartListenerCollection::ScChartListenerCollection( const ScChartListenerCollection& rColl ) : + meModifiedDuringUpdate( SC_CLCUPDATE_NONE ), pDoc( rColl.pDoc ) { aTimer.SetTimeoutHdl( LINK( this, ScChartListenerCollection, TimerHdl ) ); @@ -441,12 +443,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); } @@ -519,6 +525,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. @@ -550,6 +559,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. @@ -594,6 +606,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) { @@ -601,9 +618,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() |