fix(fspy): tolerate torn shared-memory frames when collecting traced accesses#545
fix(fspy): tolerate torn shared-memory frames when collecting traced accesses#545wan9chi wants to merge 1 commit into
Conversation
Add a `vtt corrupt-fspy-shm` helper that appends a torn frame to the task's fspy shared-memory channel: the end offset covers the frame's extent, the frame header is still zero, and path-like content bytes are present. This is the exact byte-level state a tracked writer leaves behind when it dies or races the reader between claiming a frame and completing it, and the writer API can never produce it on its own, so the helper reconstructs it through raw shared-memory writes (via a new `ChannelConf::shm_id` accessor and the payload fspy hands every traced process). The new fspy_shm_torn_frame e2e fixture runs such a task twice: today `vp run` panics in `ShmReader::iter_frames` after the task itself succeeded, with the exact bogus skip length from the issue (1919954688 = 0x72702F00 = "\0/pr" path bytes read as a frame header). The snapshot captures the crash to demonstrate the bug; the follow-up commit makes the reader degrade gracefully and updates the snapshot. The fixture is skipped on musl because the shared-memory channel does not exist there (fspy uses seccomp-unotify arenas instead). Issue: #544 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ps7hxpYTqwk3t9qnPgyK8
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 43da79ec8d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| ## `vt run -v torn-frame` | ||
|
|
||
| **Exit code:** 101 |
There was a problem hiding this comment.
Assert the non-panicking torn-frame behavior
The new regression fixture currently passes only when vt run exits 101 and prints the same fspy slice-bounds panic. That locks in the #544 failure mode instead of proving the reader tolerates the torn frame; the fixture comment says this must not crash and must avoid caching incomplete data, so the expected snapshot should be the graceful exit-0/not-cached result for both runs.
Useful? React with 👍 / 👎.
Motivation
Closes #544.
vp runcan crash with a slice-bounds panic while collecting fspy path accesses after the task itself completed successfully:ShmReader::iter_framesassumes writer quiescence. When a tracked writer dies — or is still writing — between claiming a frame and completing it, the buffer is left with a torn frame: the end offset already covers the frame's extent, the frame header is still zero, but content bytes are present. The reader's zero-header arm then steps 4 bytes at a time into that extent and misreads frame content (path bytes) as a frame header:1919954688 = 0x72702F00is exactly"\0/pr"from an absolute path. The resulting bogus skip length overruns the used region and panics — or, worse, a misparse that stays in bounds could silently corrupt the inferred inputs/outputs that feed the cache.The live race window is nanoseconds wide (see the issue's fresh-relink correlation), so the reproduction crafts the torn byte-state deterministically instead of racing.
Approach
Two commits, meant to be read in order:
test(e2e): reproduce fspy shm reader panic on torn frame (#544)— adds avtt corrupt-fspy-shmtest helper that opens the task's own fspy channel (via the payload fspy hands every traced process) and appends the torn-frame state through raw shared-memory writes — the writer API can never produce it on its own. The newfspy_shm_torn_framee2e fixture runs such a task twice; the snapshot at this commit captures the crash, byte-for-byte matching the issue (same bogus header value, same panic site). CI on this commit is green with the panic snapshot, demonstrating the bug is reproduced stably on every platform with the shared-memory channel (the fixture is skipped on musl, where the channel doesn't exist and fspy uses seccomp-unotify arenas instead).fix(fspy): treat torn shm frames as truncated tail instead of panicking— makes the reader defensive, following the issue's suggestion:ShmReader::iter_framesstops (instead of panicking) when a frame's recorded extent overruns the used region, and reports it viais_tail_truncated();unwrap()-panicking;update_cache, which skips caching with a newTrackingIncompletereason — mirroring howFspyUnsupporteddegrades — because the inferred inputs/outputs may be missing entries and a cache entry built from them could produce stale hits;→ Not cached: file access tracking data was incomplete.The e2e snapshot is updated to prove it: the run now exits 0 with the not-cached notice, and the second run stays a cache miss (nothing bogus was cached).
The root-cause audit of receiver-lock coverage (which descendants can write without holding the shared flock) and acquire-ordering for a non-quiescent reader remain follow-up work per the issue; this PR removes the crash and the unsound caching path regardless of which hypothesis produces the torn state.
🤖 Generated with Claude Code
https://claude.ai/code/session_017ps7hxpYTqwk3t9qnPgyK8
Generated by Claude Code