summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2014-11-15 02:00:16 +0100
committerEike Rathke <erack@redhat.com>2014-11-15 02:08:34 +0100
commitef2ed50231fd946c1f374ffbce28ebb98eda56c5 (patch)
treec50e88c7d655bdd3969857cfa1dbe080c900ae89
parent0b3766645d7d52d5c2022b1e8e4617eff06403c8 (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.hxx6
-rw-r--r--sc/source/core/tool/chartlis.cxx21
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()