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

Eike Rathke erack at redhat.com
Mon Nov 6 18:41:00 UTC 2017


 sc/inc/document.hxx              |   18 +++++++++
 sc/source/core/data/documen7.cxx |   71 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 87 insertions(+), 2 deletions(-)

New commits:
commit efdf57aa44bd22a799d76ec67c805bc5c2d91678
Author: Eike Rathke <erack at redhat.com>
Date:   Mon Nov 6 19:39:26 2017 +0100

    ofz#4052 limit listener range to actually available sheets
    
    ... instead of an arbitrary reference range read from a binary
    file format, here 4k sheets resulting in >3GB allocated listener
    memory.
    
    Change-Id: I629297f4249fdf16a0ede098b63d9648fda69ac3

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index a2a073a68ab2..31c5e2f4957a 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2046,6 +2046,24 @@ private:
 
     static ScRecursionHelper*   CreateRecursionHelperInstance();
 
+    /** Adjust a range to available sheets.
+
+        Used to start and stop listening on a sane range. Both o_rRange and
+        o_bEntirelyOutOfBounds are set only if needed and don't have to be
+        initialized by the caller.
+
+        @param  o_bEntirelyOutOfBounds
+                <TRUE/> if both sheets in the range point outside the
+                available sheet range, in which case no adjustment is done and
+                o_rRange is not modified.
+
+        @return <TRUE/> if any adjustment was done or o_bEntirelyOutOfBounds
+                was set <TRUE/>.
+                <FALSE/> if rRange was within the available sheets.
+     */
+    bool                LimitRangeToAvailableSheets( const ScRange& rRange, ScRange& o_rRange,
+                                                     bool& o_bEntirelyOutOfBounds ) const;
+
 public:
     void StartListeningArea( const ScRange& rRange, bool bGroupListening, SvtListener* pListener );
 
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index da50d2aa4146..4340827035cb 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -44,14 +44,81 @@
 void ScDocument::StartListeningArea(
     const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
 {
-    if ( pBASM )
+    if (!pBASM)
+        return;
+
+    // Ensure sane ranges for the slots, specifically don't attempt to listen
+    // to more sheets than the document has. The slot machine handles it but
+    // with memory waste. Binary import filters can set out-of-bounds ranges
+    // in formula expressions' references, so all middle layers would have to
+    // check it, rather have this central point here.
+    ScRange aLimitedRange( ScAddress::UNINITIALIZED );
+    bool bEntirelyOut;
+    if (!LimitRangeToAvailableSheets( rRange, aLimitedRange, bEntirelyOut))
+    {
         pBASM->StartListeningArea(rRange, bGroupListening, pListener);
+        return;
+    }
+
+    // If both sheets are out-of-bounds in the same direction then just bail out.
+    if (bEntirelyOut)
+        return;
+
+    pBASM->StartListeningArea( aLimitedRange, bGroupListening, pListener);
 }
 
 void ScDocument::EndListeningArea( const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
 {
-    if ( pBASM )
+    if (!pBASM)
+        return;
+
+    // End listening has to limit the range exactly the same as in
+    // StartListeningArea(), otherwise the range would not be found.
+    ScRange aLimitedRange( ScAddress::UNINITIALIZED );
+    bool bEntirelyOut;
+    if (!LimitRangeToAvailableSheets( rRange, aLimitedRange, bEntirelyOut))
+    {
         pBASM->EndListeningArea(rRange, bGroupListening, pListener);
+        return;
+    }
+
+    // If both sheets are out-of-bounds in the same direction then just bail out.
+    if (bEntirelyOut)
+        return;
+
+    pBASM->EndListeningArea( aLimitedRange, bGroupListening, pListener);
+}
+
+bool ScDocument::LimitRangeToAvailableSheets( const ScRange& rRange, ScRange& o_rRange,
+        bool& o_bEntirelyOutOfBounds ) const
+{
+    if (rRange == BCA_LISTEN_ALWAYS)
+        return false;
+
+    const SCTAB nMaxTab = GetTableCount() - 1;
+    if (ValidTab( rRange.aStart.Tab(), nMaxTab) && ValidTab( rRange.aEnd.Tab(), nMaxTab))
+        return false;
+
+    SCTAB nTab1 = rRange.aStart.Tab();
+    SCTAB nTab2 = rRange.aEnd.Tab();
+    SAL_WARN("sc.core","ScDocument::LimitRangeToAvailableSheets - bad sheet range: " << nTab1 << ".." << nTab2 <<
+            ", sheets: 0.." << nMaxTab);
+
+    // Both sheets are out-of-bounds in the same direction.
+    if ((nTab1 < 0 && nTab2 < 0) || (nMaxTab < nTab1 && nMaxTab < nTab2))
+    {
+        o_bEntirelyOutOfBounds = true;
+        return true;
+    }
+
+    // Limit the sheet range to bounds.
+    o_bEntirelyOutOfBounds = false;
+    nTab1 = std::max<SCTAB>( 0, std::min( nMaxTab, nTab1));
+    nTab2 = std::max<SCTAB>( 0, std::min( nMaxTab, nTab2));
+    o_rRange = rRange;
+    o_rRange.aStart.SetTab(nTab1);
+    o_rRange.aEnd.SetTab(nTab2);
+    return true;
 }
 
 void ScDocument::Broadcast( const ScHint& rHint )


More information about the Libreoffice-commits mailing list