fix(graph): don't panic hashing a spec with a Subset build-dep - #693
Conversation
build_attrs_hash filtered build_deps with `.filter(|i| i.as_build().is_none())`, which only excludes the Build variant — so a BuildDep::Subset fell through to build_input_hash, whose `Build(_) | Subset(_) => unreachable!()` arm panicked. Subset build-deps are a real, supported state (constructed in loader.rs:116, and SpecHasher::process already handles them as edges), so hashing any spec with one aborted the process. Exclude Subset from the inline-input pass too; it's already hashed as an edge. No existing hash changes (specs without subset build-deps are unaffected; specs with them previously panicked), so there is no cache invalidation. Adds a regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 39 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Comment |
…uzzing guide (#1106) * test: add cargo-fuzz harnesses for the untrusted-decode boundary Adds eight fuzz targets over the code that turns attacker-influenceable bytes into in-memory structures — the sharpest trust boundary in the tree: graph_from_bytes Graph::from_bytes (remote-execution wire format) graph_roundtrip structure-aware from_bytes(to_bytes(g)) == g remote_index_from_reader IndexFile::from_reader (index.shisha) [Linux only] spec_hash_from_hex SpecHash::from_hex target_from_str Target::from_str mfile_from_toml minimal.toml through the custom serde visitors arg_schema_parse ArgSchema::try_from jq_parse_json jq::parse_file, JSON branch Each fuzz/ dir is its own workspace so the nightly + sanitizer build cannot perturb the main one. Three small production hooks are needed: * graph: `Graph::fuzz_roundtrip` behind a new off-by-default `fuzzing` feature (graphs are not hand-constructible from outside the crate), and `insert_build` gated on `any(test, feature = "fuzzing")` rather than test alone. Default builds are unchanged. * mfile: `File::from_toml_bytes`, the pure filesystem-free core of `from_dir`, so the harness need not re-implement it. * workspace: `arbitrary`, optional and only enabled by graph's `fuzzing`. Also carries the graph corpus seeds; a valid graph-with-local-file seed is what let the fuzzer reach the local-file frame decoder. This is the tooling behind the six decoder fixes already merged in #651, #653, #656, #661 and #693. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * build(justfile): add fuzz-check bitrot guard and a fuzz runner Each fuzz/ dir declares its own [workspace], so no workspace-wide build ever compiles the fuzz targets and they rot silently as the crates they fuzz evolve. The first version of this suite went 253 commits before anyone rebuilt it, by which point a target referenced a renamed type. `just fuzz-check` is the guard: a plain `cargo check` over every fuzz workspace. No nightly, no sanitizer, no libFuzzer runtime — just "does this still compile against today's API", so it runs anywhere and is cheap enough to treat like a red build. `just fuzz <crate> <target> [args]` runs one target, applying the RSS cap that turns an unbounded-allocation bug into a catchable crash rather than an ambient OOM. The rcache target is excluded on macOS (rcache -> lcache -> the Linux-only common::renameat2), following the existing `scope` idiom. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: add the fuzzing guide Covers prerequisites, the eight targets and their trust levels, running via the just recipes, corpus seeding (and why seeding is what unlocks the deep decode paths), reproducing and minimizing a crash, keeping targets from bitrotting, the bugs the campaign found, and where to take it next. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
A
BuildDep::Subsetinbuild_depscrashes spec-hash computation.build_attrs_hash(spec_hasher.rs:244) filtered build_deps with.filter(|i| i.as_build().is_none()), which only excludes theBuildvariant. ASubsettherefore reachedbuild_input_hash, whose first arm isBuild(_) | Subset(_) => unreachable!()(:167) -> panic.Subset build-deps are a real state:
loader.rs:116constructs them andSpecHasher::process(:106) already handles them as edges. So hashing any spec with a subset build-dep aborts the process (spec-hash is computed during planning/build, so this is not niche).Fix: exclude
Subsetfrom the inline-input pass (it is already hashed as an edge by index). No hash values change — specs without subset build-deps are byte-identical, and specs with them previously panicked — so there is zero cache invalidation. Regression test included (it panics before the fix, passes after).Found during an Aeneas/Lean formal-verification scoping pass on the spec hasher; a broader tracking issue (collision/prefix-free rewrite + verification roadmap) is coming separately.
🤖 Generated with Claude Code