sc/source/core/data/dociter.cxx |   24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

New commits:
commit 78a66f99958ed258686cb2fac90f361954b5afe4
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Mar 20 00:41:00 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Thu Mar 20 06:10:04 2025 +0100

    tdf#165821: don't change range of ScCellIterator outside of wanted bounds
    
    Commit 8e3a29110c8ad739bedeea90932663608d8d3935 (ofz#20904 check bounds,
    2020-02-29) workarounded an out-of-bounds access, by changing maStartPos
    to be in the allocated range. But that meant that functions that wanted
    the data from some specific range, got the data from another.
    
    Fix this by looking for table in the wanted range that has the allocated
    columns in the wanted range (cf. to ScCellIterator::getCurrent(), which
    skips the unallocated area altogether). If no tables have such columns,
    just initialize maCurPos with an unvalid table, which causes first() to
    return false (the same as with invalid tables).
    
    No idea how to make a unit test for this. Adding a formula like
    
    =COUNTA(ABC:ABC)
    
    to the end of sc/qa/unit/data/functions/statistical/fods/counta.fods,
    with expected value of 0, doesn't fail without the fix.
    
    Change-Id: I570cf4a11a410b4e79eb4df785d6c52897973b6e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183141
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index 00309ceb871b..6b90faf2b06e 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -875,17 +875,29 @@ void ScCellIterator::init()
     while (maEndPos.Tab() > 0 && !mrDoc.maTabs[maEndPos.Tab()])
         maEndPos.IncTab(-1); // Only the tables in use
 
-    if (maStartPos.Tab() > maEndPos.Tab())
-        maStartPos.SetTab(maEndPos.Tab());
-
-    if (!mrDoc.maTabs[maStartPos.Tab()])
+    if (maStartPos.Tab() > maEndPos.Tab() || !mrDoc.maTabs[maStartPos.Tab()])
     {
         assert(!"Table not found");
-        maStartPos = ScAddress(mrDoc.MaxCol()+1, mrDoc.MaxRow()+1, MAXTAB+1); 
// -> Abort on GetFirst.
+        maStartPos = ScAddress(mrDoc.MaxCol()+1, mrDoc.MaxRow()+1, MAXTAB+1); 
// -> Abort on first().
     }
     else
     {
-        
maStartPos.SetCol(mrDoc.maTabs[maStartPos.Tab()]->ClampToAllocatedColumns(maStartPos.Col()));
+        for (auto tabNo = maStartPos.Tab();; ++tabNo)
+        {
+            const auto& pTab = mrDoc.maTabs[tabNo];
+            if (pTab && maStartPos.Col() < pTab->GetAllocatedColumnsCount())
+            {
+                // Found the first table with allocated columns in range
+                maStartPos.SetTab(tabNo);
+                break;
+            }
+            if (tabNo == maEndPos.Tab())
+            {
+                // No allocated columns found in the range -> return false 
from first().
+                maStartPos = ScAddress(mrDoc.MaxCol() + 1, mrDoc.MaxRow() + 1, 
MAXTAB + 1);
+                break;
+            }
+        }
     }
 
     maCurPos = maStartPos;

Reply via email to