Skip to content

XSSF: validate row/column/cell index before mutating the sheet XML - #3

Merged
ken-swyfft merged 9 commits into
masterfrom
fix/ks/20260724_xssf-validate-index-before-mutating-sheet-xml
Sep 9, 2026
Merged

ken-swyfft merged 9 commits into
masterfrom
fix/ks/20260724_xssf-validate-index-before-mutating-sheet-xml

Conversation

@ken-swyfft

Copy link
Copy Markdown
Member

Fork-side copy of the fix submitted upstream as nissl-lab/npoi#1825.

XSSFSheet.CreateRow adds the row element to sheetData before XSSFRow.RowNum validates the index, so a rejected index leaves an orphaned row in the XML — invisible to the object model, still written to the file. Repeated failed probes produce rows with duplicate r values, ahead of the real rows, and Excel reports the workbook as corrupt and strips the sheet's data when repairing it. CreateColumn and XSSFRow.CreateCell have the same mutate-then-validate shape.

This is the library-side half of SW-53290; swyfft_web#21903 fixes the call site that was feeding -1 into the adapter. Either fix alone prevents the corruption — this one closes it for every future caller, including the upper-bound case the call-site guard doesn't cover.

Exception types and messages are unchanged; the existing BaseTestRow bounds assertions still hold. Four new tests cover the three creation methods plus an end-to-end check that inspects the persisted part XML. Full NPOI.OOXML.TestCases suite passes on net10.0 (1872 tests); net472 failures are pre-existing and identical before and after.

Packaged as 2.8.0-swyfft.2.

(PR opened by Claude, an AI assistant, on Ken's behalf.)

stevenaw and others added 5 commits May 16, 2026 22:10
XSSFSheet.CreateRow adds the row element to sheetData before XSSFRow's
RowNum setter validates the index. When the setter rejects the index the
element is already in the XML, and because _rows is only updated after
validation the row is orphaned: invisible to GetRow and
PhysicalNumberOfRows, but still written to the file.

The result is a workbook Excel refuses to open. Each leaked row carries
the same r attribute — XSSFRow's constructor fills in LastRowNum + 2 for
an unset r before the setter throws — so the rows are duplicated and
precede the real ones, breaking the required ascending order. Excel
reports "We found a problem with some content" and strips the sheet's
data when repairing it. A caller only has to probe a name that doesn't
resolve and catch the exception, which is what "does this optional cell
exist?" code does, for the saved file to be corrupt.

XSSFSheet.CreateColumn and XSSFRow.CreateCell have the same
mutate-then-validate shape. CreateColumn leaves a col definition for a
column that was never created; the orphaned cell does not reach the file
today only because XSSFRow.OnDocumentWrite rebuilds the row's cell array
when the counts disagree.

Hoist the checks so nothing is written until the index is known good.
The peers already do it this way — SXSSFSheet.CreateRow, SXSSFRow
.CreateCell, XSSFColumn.CreateCell and XSSFRow.GetCell all validate
first, as does HSSFSheet.CreateRow — so this makes XSSF consistent with
the rest of the library. Exception types and messages are unchanged.
NuGet audit fails restore on the 10.0.6 pins — five high-severity
advisories against System.Security.Cryptography.Xml, promoted to errors
by Warning As Error in NPOI.Benchmarks, which takes down restore for the
whole test solution and so every CI run. Bumping the crypto package
alone trips NU1109 because System.Formats.Asn1 is pinned at 10.0.6 and
Microsoft.Bcl.Cryptography 10.0.10 wants 10.0.10, so both move together.

Restore is clean with the audit enabled and the full test solution
passes on net10.0 (2803 + 1868 + 79).
…xception type

- GetWrittenSheetXml opens the package read-only, disposes the stream and
  drops RegexOptions.Compiled from a single-use regex.
- Match the file's 'for (' spacing.
- XSSFCell.CheckBounds documented as throwing ArgumentException, not
  RuntimeException (a Java leftover on the line this patch touched).
Folds in the NuGet audit fix so this branch restores cleanly and CI can
actually run the new tests.
ken-swyfft and others added 3 commits July 24, 2026 19:45
NuGet audit fails restore on the 10.0.6 pins — five high-severity
advisories against System.Security.Cryptography.Xml, promoted to errors
by Warning As Error in NPOI.Benchmarks, which takes down restore for the
whole test solution and so every CI run. Bumping the crypto package
alone trips NU1109 because System.Formats.Asn1 is pinned at 10.0.6 and
Microsoft.Bcl.Cryptography 10.0.10 wants 10.0.10, so both move together.

Restore is clean with the audit enabled and the full test solution
passes on net10.0 (2803 + 1868 + 79).
…ader

Optimize PngUtils.MatchesPngHeader()
…ump-cryptography-xml

Bump System.Security.Cryptography.Xml and System.Formats.Asn1 to 10.0.10 (fixes CI)
…ssf-validate-index-before-mutating-sheet-xml
@ken-swyfft
ken-swyfft merged commit ca9f50c into master Sep 9, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants