[Libreoffice-commits] core.git: sc/inc sc/source

Eike Rathke erack at redhat.com
Fri Nov 14 17:09:00 PST 2014


 sc/inc/chartlis.hxx              |    6 ++++++
 sc/source/core/tool/chartlis.cxx |   21 +++++++++++++++++++++
 2 files changed, 27 insertions(+)

New commits:
commit ef2ed50231fd946c1f374ffbce28ebb98eda56c5
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

diff --git a/sc/inc/chartlis.hxx b/sc/inc/chartlis.hxx
index f9a3641..9952d4b 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 be56325..837dbfe 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()


More information about the Libreoffice-commits mailing list