[Libreoffice-commits] core.git: Branch 'libreoffice-4-3' - sc/inc sc/source
Eike Rathke
erack at redhat.com
Fri Nov 14 22:12:32 PST 2014
sc/inc/chartlis.hxx | 6 ++++++
sc/source/core/tool/chartlis.cxx | 21 +++++++++++++++++++++
2 files changed, 27 insertions(+)
New commits:
commit 547d613e0868726e602ccb00fca0e7518a6c4bee
Author: Eike Rathke <erack at 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.mohrhard at googlemail.com>
Tested-by: Markus Mohrhard <markus.mohrhard at 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()
More information about the Libreoffice-commits
mailing list