crashtesting: unshare formula cells the matrix import overwrites
ScDocumentImport::setMatrixCells places the matrix master and its
reference cells with raw cell-store set() calls. set() destroys the
cell it overwrites with no shared-formula bookkeeping, so a group
whose member dies that way is left with a stale length, or with a
dead top cell that the next Interpret of a surviving member
dereferences (formulacell.cxx:1560).
The xlsx import builds exactly such groups from stacked dynamic
arrays: the empty <f ca="1"/> spill placeholders of adjacent rows
compile to identical empty token arrays, and applyCellFormulas puts
vertical runs of identical formulas into one group. Materialising the
upper row's array then destroys the lower row's group top.
A member surviving its top cell's destruction became reachable since:
commit e4476c8072af0d825578f5222935718a159bb383
Date: Wed May 6 23:33:16 2026 +0900
sc: Preserve #SPILL! state through XLSX and ODS import
which keeps the cells of a spill-flagged array's range alive instead
of overwriting them all. Detach the doomed cell from its group before
each set().
Reproduced with forum-mso-en4-756517.xlsx and forum-mso-en4-756511.xlsx
from interop-test-files, soffice --headless --convert-to xlsx, dbgutil
build.
Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Change-Id: Ic347cee8c30b0d93919173a85fdd42cfd8a208e9
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4723
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
(cherry picked from commit 2f74f677ce588c1ecbf3370c08a85ef94d49313e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207397
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
committed by
Xisco Fauli
parent
6e6ad8e4c1
commit
855da692bc
@@ -46,6 +46,19 @@ struct TabAttr
|
||||
std::vector<ColAttr> maCols;
|
||||
};
|
||||
|
||||
// The cell store's set() destroys the cell it overwrites with no shared
|
||||
// formula bookkeeping, so a group whose member dies that way is left with a
|
||||
// stale length, or with a dead top cell that the next Interpret of a
|
||||
// surviving member dereferences. Detach the doomed cell from its group first.
|
||||
void unshareDoomedCell(sc::CellStoreType& rCells, const sc::CellStoreType::iterator& itHint, SCROW nRow)
|
||||
{
|
||||
sc::CellStoreType::position_type aPos = rCells.position(itHint, nRow);
|
||||
if (aPos.first->type != sc::element_type_formula)
|
||||
return;
|
||||
ScFormulaCell& rCell = *sc::formula_block::at(*aPos.first->data, aPos.second);
|
||||
sc::SharedFormulaUtil::unshareFormulaCell(aPos, rCell);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct ScDocumentImportImpl
|
||||
@@ -423,6 +436,7 @@ void ScDocumentImport::setMatrixCells(
|
||||
|
||||
mpImpl->mrDoc.CheckLinkFormulaNeedingCheck( *pCell->GetCode());
|
||||
|
||||
unshareDoomedCell(rCells, pBlockPos->miCellPos, rBasePos.Row());
|
||||
pBlockPos->miCellPos =
|
||||
rCells.set(pBlockPos->miCellPos, rBasePos.Row(), pCell);
|
||||
|
||||
@@ -460,6 +474,7 @@ void ScDocumentImport::setMatrixCells(
|
||||
*ScRefTokenHelper::getSingleRef(t) = aRefData;
|
||||
ScTokenArray aTokArr(aArr.CloneValue());
|
||||
pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, aTokArr, eGram, ScMatrixMode::Reference);
|
||||
unshareDoomedCell(rCells, pBlockPos->miCellPos, aPos.Row());
|
||||
pBlockPos->miCellPos =
|
||||
rCells.set(pBlockPos->miCellPos, aPos.Row(), pCell);
|
||||
}
|
||||
@@ -480,6 +495,7 @@ void ScDocumentImport::setMatrixCells(
|
||||
*ScRefTokenHelper::getSingleRef(t) = aRefData;
|
||||
ScTokenArray aTokArr(aArr.CloneValue());
|
||||
pCell = new ScFormulaCell(mpImpl->mrDoc, aPos, aTokArr, eGram, ScMatrixMode::Reference);
|
||||
unshareDoomedCell(rColCells, pBlockPos->miCellPos, aPos.Row());
|
||||
pBlockPos->miCellPos =
|
||||
rColCells.set(pBlockPos->miCellPos, aPos.Row(), pCell);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user