Skip to content

fix(analyzer): tolerate malformed qpc_freq / truncated rows instead of crashing#19

Merged
mledour merged 1 commit into
mainfrom
fix/analyzer-tolerant-parse
Jun 8, 2026
Merged

fix(analyzer): tolerate malformed qpc_freq / truncated rows instead of crashing#19
mledour merged 1 commit into
mainfrom
fix/analyzer-tolerant-parse

Conversation

@mledour

@mledour mledour commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Finding #8 (code review): analyzer crashes where the C++ merge degrades

analyze.py parsed the qpc_freq header and every data row with bare int(). So a non-integer # qpc_freq= value (1e7, 10 MHz) or a half-flushed / short data row (a crash mid-write) raised an uncaught ValueError/IndexError and aborted the whole analyzer — whereas the in-DLL C++ merge tolerates both (StrictStoll falls back to the 10 MHz default; ReadFrameCsv/ReadGpuCsv skip a row whose four fields don't all extract). The two documented-equivalent paths thus diverged on corrupt input: one crashes, the other degrades.

Fix — mirror the C++ behavior

  • qpc_freq: fall back to DEFAULT_QPC_FREQ (10 MHz) on a parse failure (matches StrictStoll).
  • data rows: skip via a _parse_int4 helper that returns None on ValueError/IndexError, with a stderr count of how many were dropped (matches the C++ row-skip).

The loud header-mismatch guard (wrong column header → SystemExit) is kept — that catches "you passed the merged CSV by mistake", a different, deliberate case.

Verification (ran locally)

Two new tests — a malformed qpc_freq header and a truncated 3-field data row — now both produce output (rc 0) instead of a traceback, with the valid frames still merged:

$ python3 -m pytest scripts/test_analyze.py -q
19 passed

CI also runs this suite. No lines >99 cols.

🤖 Generated with Claude Code

…f crashing

analyze.py parsed the qpc_freq header and every data row with bare int(), so a
non-integer "# qpc_freq=" value ("1e7", "10 MHz") or a half-flushed / short
data row (a crash mid-write) raised an uncaught ValueError/IndexError and
aborted the whole analyzer -- whereas the in-DLL C++ merge tolerates both
(StrictStoll falls back to the 10 MHz default; ReadFrameCsv/ReadGpuCsv skip a
row whose fields don't all extract). The two "equivalent" paths thus diverged
on corrupt input: one crashed, the other degraded.

Mirror the C++ behavior:
  * qpc_freq: fall back to DEFAULT_QPC_FREQ (10 MHz) on a parse failure;
  * data rows: skip via a _parse_int4 helper that returns None on
    ValueError/IndexError, with a stderr count of how many were dropped.
The loud header-mismatch guard (wrong column header => SystemExit) is kept --
that catches "you passed the merged CSV by mistake", a different case.

Tests: a malformed qpc_freq header and a truncated data row now both produce
output (rc 0) instead of a traceback; 19/19 pass locally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mledour mledour merged commit d5664cd into main Jun 8, 2026
3 checks passed
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.

2 participants