Repository navigation
fix(pin-census): a line break, TAB or | inside an id split the census row - #260
Conversation
… row A C++ out-of-line member of a class template whose template-argument list spans source lines has a scope holding that line break verbatim, and --pin-census wrote ids raw. One C row became a 6-field line plus a continuation line starting with neither C/S/O nor #, and the symbol's S row broke the same way (seen once on a large private C++ corpus). The map never had the defect: escapeXml writes the same scope as . Five more spellings reproduce on the pre-fix binary: a TAB or a form feed in the argument list, a backslash line splice, CRLF source, and a | inside an id, which is the targets separator. The fix: every id and callee field goes through appendCensusField (a Byteset256 + appendCleanRun escaper, the escapeXml shape): \ -> \\, TAB/LF/CR -> \t \n \r, every other C0 byte and | -> \xHH. Columns are unchanged and an id without those bytes is byte-identical to v2; the header line says v3 and documents the escape. bench/scip_match_diag.py decodes the fields (it opens files by an id's path); scip_pin_precision.py joins ids as opaque keys. Measured, pre-fix vs fixed binary over a clean `git archive a55b118` export: 99 of 51,821 rows change (18 C, 81 S; 98 hold |, 1 a backslash) and all 99 decode back to their pre-fix bytes; the 18 C rows are Markdown-heading targets such as `--token-budget=N[K|M|G]` that a |-split read as 2-6 targets (18 misread before, 0 after). Every other row is byte-identical. Gate: test/pincensuscheck.sh arm (L), over a generated fixture (a pipe|dir directory, CRLF and TAB bytes are never committed). Every non-comment line is a C/S/O row with its field count (also over the (B) and (G) censuses); each awkward caller id decodes to its source bytes, re-encodes identically and is an S id verbatim; the | target splits to one id; dispositions and summary counts match what a line reader parses; a control un-escapes one C row and the same shape check sees it. (B) now expects v3. The \xHH digits come from a constexpr table, not a format call into a char[] (test/fixedbufsweep.sh refuses an unclassified fixed buffer), and a form-feed case holds the zero-padded low-byte path to the documented rule. Red on the pre-fix binary: 12 FAIL (a line reader parsed 2 of 6 C rows and 12 of 16 S ids). Green: 52 PASS, also under ./asan/ripwire, which reports nothing over the census fixtures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Main added help-wanted prompt docs only; no gate, source or pin moved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CHANGELOG.md conflicted on the Unreleased insertion point: main's entries (#246 Xcode 26.6, #241 cached enum byte) are kept first and this lane's entry follows them. No other file conflicted; the gate-count and LIMITS generators still agree with the merged tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CHANGELOG.md conflicted on the Unreleased insertion point again: #250's entry is kept first and this lane's entry follows it. No other file conflicted and no other file overlaps this lane; the gate-count and LIMITS generators agree with the merged tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (5)
Included review availability: Your plan provides up to 8 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthroughChangesPin census v3 field escaping
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to The v3 escaping change has no identified merge-blocking risk and is ready to merge after normal checks. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 4 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
Takes #258, #260 and #261. No conflicts. The two files both sides touch are CHANGELOG.md, where every entry is kept, and test/estchargecheck.sh, where main re-points the alert-observability probe from --since=notadate (a refusal since M8) to a --scip decode failure. This lane's #14f and #14g arms read the same alerts_observable/ndebug_flavour pair and sit below the moved hunk, so they run on the plain build and skip on an NDEBUG one exactly as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…through the template-scope defect redhat-et#256 fixes The full suite at f90e067 read gates=639 pass=635 skip=3 fail=1: pincensuscheck arm (L) (from redhat-et#260, the census field escape). Its fixture put a line break, a backslash splice, a TAB, a form feed and CRLF into ids through C++ out-of-line members of a class template whose argument list kept those bytes in the scope (`SmallVec<T, Alloc,\n GrowingPolicy, N>::grow`). redhat-et#256 keys that scope as the bare template name, so all five presence guards correctly reported the fixture no longer reaches the byte. The fixture now reaches the same five bytes through C++ CONVERSION OPERATORS, whose symbol name is the written type verbatim (`operator Pair<int,\n long>`, `operator Pair<char, \\\nshort>`, `operator Pair<bool,\tfloat>`, `operator Pair<double,\fint>`, and a CRLF `operator Pair<long,\r\n int>`); the presence guards read the map's n= instead of sc=, under the same xmlspell rule. The checker, the verdict count and the `|`-in-path case are unchanged. Evidence: pincensuscheck ALL PASS (52) on this train's binary; on b1489df (before the escape) the (L) round-trip and shape arms fail (12 FAIL, misshapen rows), so the arm keeps its failing state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Defect
--pin-census=FILEwrites TSV rows (C rows have 9 fields:C mech pre post flags caller_id callee targets line). Ids were written raw. A C++ out-of-line member of a class template whose template-argument list spans source lines has a scope that holds the line break verbatim, for exampleSmallVec<T, Alloc, SizeType,\n GrowingPolicy, N>. That split one C row into a 6-field line plus a continuation line starting with neither C, S, O nor#, and the symbol's S row broke the same way. It was seen once on a large private C++ corpus. The map was never affected:escapeXmlwrites the same scope as .Five more spellings of the defect reproduce on the pre-fix binary:
splitlines())|inside an id.|is the targets separator, sopipe|dir/far.hpp::far_helper#Nread back as two targets.On this repository the
|case is real: Markdown heading symbols such as--token-budget=N[K|M|G]made a|-split read 18 single-target C rows as 2 to 6 targets.Change
src/pincensus.h: every id and callee field goes throughappendCensusField, aByteset256+appendCleanRunescaper with the same shape asescapeXml. A backslash becomes\\, TAB/LF/CR become\t\n\r, and every other C0 byte and|become\xHH. The hex digits come from a constexpr table, not a format call into achar[], sofixedbufsweephas no new buffer to classify.|is written\x7crather than\|so that a naive split stays exact. Ids are composed raw once per symbol and escaped into their slot, and callee names are escaped into one reused buffer per writer. The resolver's names and scopes are untouched. The columns are unchanged, and an id without those bytes is byte-identical to v2. The header's first line now sayspin-census v3, and five new#lines document the escape.bench/scip_match_diag.py:parse_censusdecodes ids, callees and targets after splitting, because this harness opens files by an id's path and compares an id's name with SCIP descriptors.bench/scip_pin_precision.py: comment only. It joins ids as opaque keys, and both runs escape a given symbol the same way.Measured
git archive a55b118eexport of this repository, pre-fix vs fixed binary,--pin-census --no-cache: 99 of 51,821 rows change (18 C, 81 S). 98 of them hold|and 1 holds a backslash, all 99 decode back to their pre-fix bytes exactly, and every other row is byte-identical. All 18 of those C rows had target lists that a|-split misread (13 read as 2 targets, 4 as 3, 1 as 6); after the fix, none do. Misshapen rows on this tree: 0 before and 0 after, since the multi-line template shape does not occur here.Gate:
test/pincensuscheck.sharm (L), plus (B) now expects v3The fixture is generated in
$TMP, so apipe|dirdirectory, CRLF, TAB and form-feed bytes never enter the tree. The checker uses its own decoder and encoder for the documented rule. Arm (L) asserts:sc=spans each awkward byte, andp="pipe|dir/far.hpp"exists. These read an independent surface.\xHHpath.|target splits into one id, which decodes topipe|dir/far.hpp::far_helperand is an S id.rows=/symbols=equal what a line reader parses.\ninside a real C row makes the same shape check report misshapen lines.Red first: against the pre-fix binary the gate exits 1 with 12 FAIL rows ((B) header, the (L) header, shape, the 5 round trips, the
|target, dispositions, summary, control). After the fix: 52 PASS, exit 0. It also passes 52/52 under./asan/ripwire, and ASan/UBSan report nothing on the escape fixture,test/pincensusfixortest/scipfix --scip. The ASan and dev censuses are byte-identical.Gates run
6bf2255e(this lane merged with main at31e788ce), one uninterrupted run with no timeouts:gates=633 pass=631 skip=2 fail=0 wall=1585.4s jobs=6 tree_writes=0. The only skips are the environmental ones (argvdiffcheck, editchecknotecheck). Anasan/tree was present and freshly rebuilt, so g1freshcheck ran and passed.c9531d40, before the hex-table change, had one real FAIL:fixedbufsweeprefused thechar hex[8]+formatTosite as an unclassified fixed buffer. The table replaced it with no change to the census bytes, and the next suite ateb438c26wasgates=632 pass=630 skip=2 fail=0.105666c1, a CHANGELOG-only conflict with no other overlap) at6a436944, rebuilt and run as separate scripts: pincensuscheck (52 PASS), fixedbufsweep, declinecheck, scipjoincheck, externalvetocheck, stdqualcheck, tsimportprecisecheck, gatecountcheck, manifestcheck, limitstablecheck, gateexitcheck, printffmtparitycheck, versioncheck and xmlwellformed. All rc=0 with 0 FAIL. The full suite was not re-run on this last merge; CI covers it.docs/gatecount_build.py --checkreports 620, from main's gates, since this lane adds none.docs/limits_build.py --checkmatches (213 caps)../build/ripwire . --quality-delta=$(git merge-base origin/main HEAD)..HEADgivesregressions="0" gating="0". The remaining rows areapi-new-surface="2"(the new escaper and its byte set) and stale ack-ledger rows.--edit-checkon pinCensusIdentities, writePinCensusDecisionRows, writePinCensusOracleRows and writePinCensus reportsstatus="unchanged" incompatible="0".Pins moved
None. The census is a side file: stdout is unchanged (arm (E) still passes), and no parity manifest, legend pin, kParserVer, qschemetrip hash, gate-count marker or LIMITS row moves.
Noticed, not fixed here
An out-of-line template member such as
void Box<T>::grow()gets scopeBox<T>, notBox, so--callers=Box::growresolves to the in-class declaration and reportscount="0". That is resolver/extraction work (kParserVer), and a separate session has picked it up.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
--pin-censusoutput to format v3.|characters in IDs and callee fields.Bug Fixes