Skip to content

fix(jitdump): stop reading at records smaller than their header - #14

Merged
GuillaumeLagrange merged 2 commits into
codspeedfrom
cod-4043-jitdump-malformed-record
Oct 30, 2026
Merged

GuillaumeLagrange merged 2 commits into
codspeedfrom
cod-4043-jitdump-malformed-record

Conversation

@GuillaumeLagrange

@GuillaumeLagrange GuillaumeLagrange commented Oct 30, 2026 •

Copy link
Copy Markdown

A jitdump record whose total_size is smaller than the 16-byte record header can't be valid. linux-perf-data computes its body size as total_size - 16, which underflows, and skip_next_record() then seeks back onto the same header. Reading the file never terminates, and codspeed run hangs after the benchmark process exits.

CPython produces such files with -X perf_jit. On os.fork(), the child flushes the parent's unflushed jitdump buffer into the parent's file, and the parent later writes the same bytes again. The next "header" is then read from the middle of a record. Whether it decodes as total_size == 0 depends on the record layout, so it hangs deterministically for some code and never for other code.

Both record loops now stop at such a record and keep the symbols read so far, as for a truncated file:

  • JitDumpManager (recording)
  • JitDumpIndex::from_reader (--presymbolicate)

Testing

  • Regression tests: one per loop, on a jitdump with a type 0x1400, size 0 header. Both pass with the fix and time out without it.
  • End to end on an aarch64 macro runner, runner v5.6.0 with only this change:
    • A process mapping a crafted corrupted jitdump: the stock runner was still hung at the 120 s timeout; the patched runner finished in 4 s.
    • pytest-codspeed shard fix(mac): don't SIGKILL Apple toolchain binaries under samply record #2, which hung every time with the stock runner: the patched run completed normally. That run did not reproduce the exact corrupted layout, so the crafted case above is the direct proof.

Refs COD-4043

Skipping such a record seeks back onto the same header, so samply spun forever on jitdumps
corrupted by CPython forking with unflushed data.

Refs COD-4043

@not-matthias not-matthias left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find!

@GuillaumeLagrange
GuillaumeLagrange merged commit 2eaaf6e into codspeed Oct 30, 2026
15 checks passed
@GuillaumeLagrange
GuillaumeLagrange deleted the cod-4043-jitdump-malformed-record branch October 30, 2026 10:06
GuillaumeLagrange added a commit that referenced this pull request Oct 30, 2026
* fix(jitdump): stop reading at records smaller than their header

Skipping such a record seeks back onto the same header, so samply spun forever on jitdumps
corrupted by CPython forking with unflushed data.

Refs COD-4043

* test(jitdump): use into_queue_iter after the codspeed rebase
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