Skip to content

fuzz: pin the nightly, commit a seed corpus, cache corpus evolution#27

Merged
yipjunkai merged 4 commits into
mainfrom
fuzz/determinism
Jun 12, 2026
Merged

fuzz: pin the nightly, commit a seed corpus, cache corpus evolution#27
yipjunkai merged 4 commits into
mainfrom
fuzz/determinism

Conversation

@yipjunkai

Copy link
Copy Markdown
Owner

What

PR 3 of 3 from the CI review — the fuzz-lane determinism fixes.

Change Before After
Toolchain floating nightly (random-day reds — audit item 15) pinned nightly-2026-05-26 in both fuzz/rust-toolchain.toml and fuzz.yml's toolchain input (keep-in-sync comments); bump opportunistically with fuzz-dep PRs
Starting corpus empty every run — coverage never compounded; shallow random inputs → phantom reds (the #17 flake) committed fuzz/seeds/<target>/ — cmin-minimized, 315 files / ~13 KB content (56 bsm_price, 85 iv_solve, 55 black76_price, 54 greeks_all, 65 black76_greeks_all)
Corpus evolution discarded after every run actions/cache on corpus/<target> (run_id key + prefix restore) — the scheduled job's evolved corpus carries across runs
cargo-fuzz install source compile per run 0.13.2 via checksum-verified taiki-e/install-action
Job timeout 360 min default 30 min

The run reads both dirs — corpus/<t> (evolving working set, stays gitignored) + seeds/<t> (committed baseline) — so even a cold-cache run starts from known coverage instead of from nothing.

Verification

  • actionlint clean.
  • The pinned nightly resolves to exactly the locally-tested compiler (1.98.0-nightly 31a9463c6 2026-05-25).
  • iv_solve had no corpus anywhere; generated with a 60 s local run — no crashes.
  • Local smoke of the exact CI invocation: both dirs read (112-file merged seed corpus), INITED cov: 123 ft: 191 — full seed coverage instantly vs. starting at ~zero — 2.46 M execs in 6 s, no crashes.
  • The 60 s × 5 PR smoke on this PR runs with the seeds active: the libFuzzer log should show files found in seeds/... and a nonzero INITED coverage line.

Note: cargo audit shows the known pyo3 red (RUSTSEC-2026-0176) until the 0.29 bump lands — pre-existing, unrelated. (This PR touches fuzz/ but not fuzz/Cargo.lock, so post-#25 the audit workflow doesn't even trigger here — the red only appears via the daily cron.)

🤖 Generated with Claude Code

Three determinism fixes for the fuzz lane (PR 3 of 3 from the CI review):

- fuzz/rust-toolchain.toml: floating `nightly` -> pinned nightly-2026-05-26
  (the audit's random-day-red finding). fuzz.yml's dtolnay toolchain input
  pins the same date with a keep-in-sync comment; bump both opportunistically
  alongside fuzz dependency PRs.
- Commit fuzz/seeds/<target>/: cmin-minimized corpora (315 files, ~13 KB of
  content -- 56 bsm_price / 85 iv_solve / 55 black76_price / 54 greeks_all /
  65 black76_greeks_all). Every fuzz run previously started from an EMPTY
  corpus, so coverage never compounded and shallow random inputs produced
  phantom reds (the #17 flake). The run now reads corpus/<t> (evolving
  working set, gitignored) + seeds/<t> (committed baseline), so even a
  cold-cache run starts from known coverage. iv_solve had no local corpus;
  generated with a 60s run (no crashes).
- fuzz.yml: actions/cache on corpus/<target> with a run_id key + prefix
  restore-keys, so the scheduled job's evolved corpus carries across runs
  and coverage compounds; cargo-fuzz 0.13.2 via taiki-e/install-action
  (prebuilt, checksum-verified) instead of a per-run source compile;
  timeout-minutes: 30.

Verification: actionlint clean; the pinned nightly resolves to exactly the
locally-tested compiler (1.98.0-nightly 31a9463c6 2026-05-25); a local smoke
of the exact CI invocation (`cargo fuzz run bsm_price corpus/bsm_price
seeds/bsm_price`) reads both dirs (112-file seed corpus) and INITs at full
seed coverage (cov: 123 ft: 191), 2.46M execs in 6s, no crashes. The 60s x5
PR smoke on this PR runs with the seeds active.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
install-action ships cargo-fuzz as a static musl binary, and cargo-fuzz
defaults its build target to its own compile target -- so the prebuilt
binary built the fuzz targets for x86_64-unknown-linux-musl, where ASAN +
statically linked libc is unsupported (all five PR legs failed at build
with 'sanitizer is incompatible with statically linked libc'). Pass
--target x86_64-unknown-linux-gnu explicitly; the previously source-built
cargo-fuzz was gnu-compiled, which is why this never surfaced before.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Drop the duplicated dated-nightly input on the dtolnay step; a bare
`rustup toolchain install` in fuzz/ reads the channel from
fuzz/rust-toolchain.toml (rustup >= 1.28), so bumping the pin is a
one-line change with nothing to keep in sync.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@yipjunkai
yipjunkai merged commit 9dc75f0 into main Jun 12, 2026
27 checks passed
@yipjunkai
yipjunkai deleted the fuzz/determinism branch June 12, 2026 01:04
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.

1 participant