diff options
author | Eike Rathke <erack@redhat.com> | 2017-11-06 19:39:26 +0100 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2017-11-06 19:40:19 +0100 |
commit | efdf57aa44bd22a799d76ec67c805bc5c2d91678 (patch) | |
tree | e3ca4a7848a3612a0d51d7c5dbec617ad5c9aa13 /sc/source | |
parent | d4dca2b170ef36ab6c171c16d699d0988a8a7a11 (diff) |
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
Diffstat (limited to 'sc/source')
-rw-r--r-- | sc/source/core/data/documen7.cxx | 71 |
1 files changed, 69 insertions, 2 deletions
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 ) |