PcbDocReader: length-frame shape-based records; fix trailing-NUL misd… - #52
Open
Andrei-Errapart wants to merge 1 commit into
Open
PcbDocReader: length-frame shape-based records; fix trailing-NUL misd…#52Andrei-Errapart wants to merge 1 commit into
Andrei-Errapart wants to merge 1 commit into
Conversation
…etection ParseShapeBasedRegion guessed whether the properties block carries a trailing NUL by testing the next byte for zero. That misfires when a record has no trailing NUL and its outline count is a multiple of 256 (low byte 0x00): the count byte is consumed as the NUL, every following field shifts by one, and a garbage hole count sends the parser off the end of the storage. An Agilex board (MicroModule) hits this with a 257-vertex mid-layer region - one record in 9403 - and because BitConverter reports the overrun as a plain ArgumentException, which the catch filter did not cover, the whole PcbDoc read crashed. The records are length-framed, so use it: the SubRecord-1 length (read and previously discarded) now bounds the parse. The trailing-NUL choice is disambiguated by checking which variant makes the outline plus the length-prefixed holes land exactly on the record end, preferring the NUL when both would (preserving the old behaviour for every unambiguous record). Each record resyncs to its recorded end afterwards, so a single odd record degrades to a per-record diagnostic instead of poisoning the walk, and the outer catch now covers ArgumentException/EndOfStream so a truly corrupt storage degrades to a warning. Verified on MicroModule.PcbDoc: full read (1509 components, 9403 regions, no diagnostics) and byte-identical round-trip of both shape-based storages; the existing suite passes (857 tests).
Andrei-Errapart
force-pushed
the
FixShapeBasedTrailingNulDetection
branch
from
August 25, 2026 20:03
8ae48bf to
68f7a2e
Compare
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
ParseShapeBasedRegionguessed whether the properties block carries a trailing NUL bytesting the next byte for zero. That misfires when a record has no trailing NUL and its
outline count is a multiple of 256 (low byte
0x00): the count byte is consumed as theNUL, every following field shifts by one, and a garbage hole count sends the parser off
the end of the storage. An Agilex board (MicroModule) hits this with a 257-vertex mid-layer
region — one record in 9403 — and because
BitConverterreports the overrun as a plainArgumentException, which the catch filter did not cover, the whole PcbDoc read crashed.The records are length-framed, so the parser now uses that: the SubRecord-1 length
(read and previously discarded) bounds the parse, and the trailing-NUL choice is
disambiguated by checking which variant makes the outline plus the length-prefixed
holes land exactly on the record end.
Changes
ParseShapeBasedRegionreads the SubRecord-1 body length (previously skipped) andbounds the whole parse with it; a length that overruns the storage throws
EndOfStreamExceptioninstead of walking off the end.LandsOnRecordEndhelper: acceptthe variant whose outline and holes end exactly at the record end, preferring the NUL
when both would — preserving the old behaviour for every unambiguous record.
to its exact length produces a per-record
Warningdiagnostic instead of poisoningthe rest of the walk.
ReadShapeBasednow also coversArgumentExceptionandEndOfStreamException, so a truly corrupt storage degrades to a warning diagnosticrather than crashing the read.
Test Plan
dotnet test) — 850 passed, 0 failed, 10 skipped (tests requiring local sample files)diagnostics) and byte-identical round-trip of both shape-based storages.
Checklist
all edits are to private parsing methods in
PcbDocReader)