xlsb: don't name a sheet of this workbook for a reference into another - #717
Open
sjvrensburg wants to merge 1 commit into
Open
xlsb: don't name a sheet of this workbook for a reference into another#717sjvrensburg wants to merge 1 commit into
sjvrensburg wants to merge 1 commit into
Conversation
An `Xti` carries two indices: a supporting book, and a tab within that
book. `BrtExternSheet` used only the second, resolving it against this
workbook's sheets whatever the first said.
For a workbook that links to another one — last year's copy of itself,
most commonly — that names a real sheet of ours, records a real
dependency, and points it at the wrong place. Nothing about the result
looks wrong. The reference reads `Journal!$D$21`, `Journal` exists, and
`$D$21` is a cell.
On a workbook whose values can be checked, 18 `Xti` entries across four
supporting books: `BrtSupSelf` first, then three `BrtSupBookSrc`. The
three external ones were resolving to `Journal`, to a pivot sheet, and —
its tab index being past our last sheet — to `#Unknown`. Ten formulas
computed from them, and every one disagreed with the value Excel had
stored. The formula our reader gave as
=IF($D2="O",Journal!$D$23,Journal!$D$24)
reads `$D$23` and `$D$24` of a 13-row sheet. Excel stored 1, which is
what those cells hold in the *other* workbook.
So supporting books are now tracked in declaration order — `BrtSupSelf`
(0x0165) for this workbook, `BrtSupBookSrc` (0x0163) for another — and a
tab index resolves against our sheets only when the `Xti` names ours. A
reference into another book is written `[1]#Sheet3`, in the shape an
external reference already has, because the sheet's own name lives in
that workbook and it is not open. A workbook that declares no supporting
books at all keeps the old behaviour, every reference being local.
The two existing sentinels still outrank the book index, and a tab past
our last sheet is still `#Unknown`.
No fixture has an external link, and none can be authored for `.xlsb`.
The resolution is a free function with unit tests for each case; the
end-to-end evidence is that workbook, where these ten formulas stop
being read as local dependencies.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
An
Xticarries two indices: a supporting book, and a tab within that book.BrtExternSheetused only the second, resolving it against the sheets of theworkbook being read:
Why it matters
For a workbook that links to another one — last year's copy of itself, most
commonly — this names a real sheet of ours, records a real dependency, and
points it at the wrong place. Nothing about the result looks wrong. The
reference reads
SHEET_A!$D$21,SHEET_Aexists in this workbook, and$D$21is a cell on it. A caller has no way to tell that the formula was never talking
about this workbook at all.
On the workbook I found it on, the externals block declares four supporting
books —
BrtSupSelf(0x0165) first, then threeBrtSupBookSrc(0x0163) —and its 18
Xtientries name them:SHEET_ASHEET_B#UnknownTwelve formulas used them. Ten disagreed with the value Excel had stored; two
agreed by coincidence, the local cell happening to hold the same number as the
foreign one — which is the case that would never have been found by looking.
The evidence is arithmetic, not documentary
One of those formulas reads
and Excel stored
2.SHEET_Ais 13 rows long, so$D$21is empty and theformula could not have produced
2from it.SHEET_C!D21:D24— the sheet theself-book
Xtiat index 3 names — holds2, 0, 2, 1, which is exactly whatall six formulas of that family stored. The supporting books are copies of this
workbook, and the sheet in question sits at a different tab index in them.
(Sheet names are pseudonymised; the workbook is confidential. The arithmetic is
unaffected.)
The fix
Supporting books are tracked in declaration order, and a tab index resolves
against our sheets only when the
Xtiactually names ours. A reference intoanother book is written
[1]#Sheet3— the shape an external reference alreadyhas in this codebase — because the sheet's own name lives in that workbook and
it is not open. A workbook that declares no supporting books keeps the old
behaviour, every reference being local. The two sentinels still outrank the
book index.
xti_sheetis a free function with unit tests for each case.On test coverage, honestly
No fixture has an external link and I could not author one, for the usual
reason: no open-source tool writes XLSB. The end-to-end evidence is the
workbook above, which I cannot share — hence the arithmetic, which stands on
its own.
After this change, recomputing every formula in that workbook left zero
disagreements out of 6,677,397 evaluable formulas, down from 11. What remains
unevaluated there is two unimplemented functions and the 12 references into
workbooks that are not open — honest gaps, no decoding failures.
If you can supply or generate a
.xlsbwith an external link, I will add it.Independent of #712, #713 and my other branches; branched from
master.All 274 tests pass;
cargo fmt --checkandcargo clippy --all-targetsareclean.