Skip to content

PcbDocReader: length-frame shape-based records; fix trailing-NUL misd… - #52

Open
Andrei-Errapart wants to merge 1 commit into
issus:masterfrom
Andrei-Errapart:FixShapeBasedTrailingNulDetection
Open

PcbDocReader: length-frame shape-based records; fix trailing-NUL misd…#52
Andrei-Errapart wants to merge 1 commit into
issus:masterfrom
Andrei-Errapart:FixShapeBasedTrailingNulDetection

Conversation

@Andrei-Errapart

@Andrei-Errapart Andrei-Errapart commented Aug 25, 2026

Copy link
Copy Markdown

Summary

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 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

  • ParseShapeBasedRegion reads the SubRecord-1 body length (previously skipped) and
    bounds the whole parse with it; a length that overruns the storage throws
    EndOfStreamException instead of walking off the end.
  • Trailing-NUL detection is disambiguated via a new LandsOnRecordEnd helper: accept
    the 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.
  • Every record resyncs to its recorded end after parsing; a record that does not parse
    to its exact length produces a per-record Warning diagnostic instead of poisoning
    the rest of the walk.
  • The outer catch filter in ReadShapeBased now also covers ArgumentException and
    EndOfStreamException, so a truly corrupt storage degrades to a warning diagnostic
    rather than crashing the read.

Test Plan

  • Existing tests pass (dotnet test) — 850 passed, 0 failed, 10 skipped (tests requiring local sample files)
  • New tests added for new behavior
  • Manually verified on MicroModule.PcbDoc: full read (1509 components, 9403 regions, no
    diagnostics) and byte-identical round-trip of both shape-based storages.

Checklist

  • Code follows existing style and conventions
  • Public API changes are documented with XML doc comments (no public API changes —
    all edits are to private parsing methods in PcbDocReader)
  • No breaking changes

…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
Andrei-Errapart force-pushed the FixShapeBasedTrailingNulDetection branch from 8ae48bf to 68f7a2e Compare August 25, 2026 20:03
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.

1 participant