🤖 AI generated content
src/rootfilespec/bootstrap/streamedobject.py:71-74:
if fVersion == 0 and fByteCount >= 6:
# This class is versioned by its streamer checksum instead
(checksum,), buffer = buffer.unpack(">I")
fVersion = checksum
Spec: Buffer framing §4.1 "ROOT's byte-count heuristic is not a substitute": "That reasoning does not hold, and a reader MUST NOT adopt the heuristic." A class that declares version 0 and has base classes writes a full payload with no checksum — TH1L's byte count is 554. The rule (§4): look the class up in the file's streamer info; if some entry has fClassVersion == 0, no checksum follows, otherwise read a u32 checksum and match fCheckSum.
Evidence: reproduced on reference/root-io-spec/data/serialization/version-zero.root (payload 40 00 02 2a 00 00 40 00 02 00 …): StreamHeader(fByteCount=554, fVersion=1073742336, …) — 0x40000200, the TH1 base's byte count, eaten as a "checksum"; 10 bytes consumed where the frame is 6. Also affects TBtree (ClassDef version 0). The TODO on line 75 (uproot-issue-222.root, version 0 with byte count 2) is the same §4 case: declared version 0, no bases, no checksum.
Suggested fix: StreamHeader.read cannot apply the rule where it sits — it does not know the class name. Move the version-0 decision to (or feed it from) the dispatch site, where the class and the file's infos are known, and stop overloading fVersion with the checksum (nothing consumes it today).
Severity / size: high (silent misread on valid current-ROOT files) / M — depends on plumbing the class identity and streamer-info index into the framing layer.
Related: #67 and #22 (selection of an info by version/checksum needs the same lookup); #105.
Assisted-by: claude-code:claude-fable-5-1
src/rootfilespec/bootstrap/streamedobject.py:71-74:Spec: Buffer framing §4.1 "ROOT's byte-count heuristic is not a substitute": "That reasoning does not hold, and a reader MUST NOT adopt the heuristic." A class that declares version 0 and has base classes writes a full payload with no checksum —
TH1L's byte count is 554. The rule (§4): look the class up in the file's streamer info; if some entry hasfClassVersion == 0, no checksum follows, otherwise read au32checksum and matchfCheckSum.Evidence: reproduced on
reference/root-io-spec/data/serialization/version-zero.root(payload40 00 02 2a 00 00 40 00 02 00 …):StreamHeader(fByteCount=554, fVersion=1073742336, …)—0x40000200, theTH1base's byte count, eaten as a "checksum"; 10 bytes consumed where the frame is 6. Also affectsTBtree(ClassDefversion 0). The TODO on line 75 (uproot-issue-222.root, version 0 with byte count 2) is the same §4 case: declared version 0, no bases, no checksum.Suggested fix:
StreamHeader.readcannot apply the rule where it sits — it does not know the class name. Move the version-0 decision to (or feed it from) the dispatch site, where the class and the file's infos are known, and stop overloadingfVersionwith the checksum (nothing consumes it today).Severity / size: high (silent misread on valid current-ROOT files) / M — depends on plumbing the class identity and streamer-info index into the framing layer.
Related: #67 and #22 (selection of an info by version/checksum needs the same lookup); #105.
Assisted-by: claude-code:claude-fable-5-1