sc/inc/chartlis.hxx | 6 ++++++ sc/source/core/tool/chartlis.cxx | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+)
New commits: commit 547d613e0868726e602ccb00fca0e7518a6c4bee Author: Eike Rathke <er...@redhat.com> Date: Sat Nov 15 02:00:16 2014 +0100 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.mohrh...@googlemail.com> Tested-by: Markus Mohrhard <markus.mohrh...@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() _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits