fix(xls): decode PtgStr as a ByteString before BIFF8 - #703
Open
TaoGuerreiro wants to merge 1 commit into
Open
Conversation
A string literal inside a formula is a ShortXLUnicodeString in BIFF8
(cch, a 1-byte grbit, then the characters) but a ShortByteString in
BIFF2-5 (cch immediately followed by cch bytes, no grbit).
`parse_formula` applied the BIFF8 layout unconditionally, so on a BIFF5
workbook it treated the first character as the grbit, then read one byte
past the literal and advanced the cursor by `2 + cch` instead of
`1 + cch`. When the literal ends the rgce this panics:
range end index 11 out of range for slice of length 11
at xls.rs read_unicode_string_no_cch <- parse_formula
Since `parse_workbook` calls `parse_formula` while loading each sheet,
the panic escapes `open_workbook`, making such files unreadable — even
though the caller already tolerates formula errors via `unwrap_or_else`.
Real-world trigger: BIFF5 exports whose cells are string formulas rather
than plain values (e.g. federation exports where every cell is ="...").
Decode the pre-BIFF8 layout as a byte string, matching what
`parse_string` already does for BIFF2-5, and bound-check both branches
so a truncated literal is an error rather than a panic.
Collaborator
|
I think this is fixing the same issue as #521 Could you evaluate and confirm that. |
Collaborator
|
@TaoGuerreiro Ping on the open question above. |
Collaborator
|
@TaoGuerreiro Ping once more. |
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.
Problem
Opening some BIFF5 (Excel 5.0/95) workbooks panics instead of returning an error:
Because
parse_workbookparses formulas while loading each sheet, the panic escapesopen_workbookand the whole file becomes unreadable — even though the call site already tolerates formula errors throughunwrap_or_else.Cause
A string literal in a formula (
PtgStr, [MS-XLS] 2.5.198.89) is aShortXLUnicodeStringin BIFF8 —cch, a 1-bytegrbit, then the characters — but aShortByteStringbefore BIFF8:cchimmediately followed bycchbytes, with nogrbit.parse_formulaapplies the BIFF8 layout unconditionally, although it already computesis_pre_biff8a few lines above. On a BIFF5 stream it therefore takes the first character as thegrbit, reads one byte past the literal, and advances the cursor by2 + cchinstead of1 + cch. When the literal ends thergce, the slice overruns and panics.Actual bytes from an affected file, an 11-character literal ending the token stream:
The reader asks for 12 bytes after
cchwhere only 11 exist — hencerange end index 11 out of range for slice of length 11.This shows up on BIFF5 exports whose cells hold string formulas rather than plain values (the file that surfaced this has ~524k
Formularecords for 9536 rows — every cell is="..."). A BIFF5 file of plain values never reaches this code.Fix
Decode the pre-BIFF8 layout as a byte string with
high_byte = None, mirroring whatparse_stringalready does forBiff2..Biff5, and bound-check both branches so a truncated literal returnsXlsError::Lenrather than panicking.Tests
Three unit tests over
parse_formula: a BIFF5 literal ending thergce(panicked before this change), the BIFF8 layout with itsgrbit(unchanged behaviour), and a truncated literal that must be an error and not a panic. The existing suite passes unchanged;cargo fmt --checkandcargo clippy --all-targetsare clean.The file that surfaced this contains personal data so it is not attached, but I can produce a reduced fixture if you would like one in
tests/.