The restarted validate_pair campaign found a second crash: materialize produces f64 0x5bffffffffffffff, serde_json emits the shortest repr 1.4536774485912136e+135, and the non-`float_roundtrip` parse side (lexical concise-float over re-parsed digits) lands one ulp low — probe-verified upstream of this crate (ryu's own float parser accepts the same digits exactly; the std parser is exact; only serde_json's concise reparse drifts). The harness's structural serde round-trip assertion assumed Value equality holds for every finite f64 — upstream parse-side drift breaks that assumption on adversarial magnitudes. - assert_values_agree_with_ulp_slack replaces the bare Value equality: keys/shapes exact, numbers equal-or-within-one-ulp (bit diff ≤ 1) - the exact artifact bytes pinned as corpus seed-047, plus deterministic minimal forms as seed-045/seed-046 (45→48 seeds) - upstream note: enabling serde_json's float_roundtrip feature would remove the drift; the crate pins serde_json default features + preserve_order by design, so the slack is the honest pin Verification: corpus replay 30/30 green (48 seeds), fuzz build clean, clippy -D warnings clean.
alktype fuzzing
cargo-fuzz targets for the binary struct engine's untrusted-input
surfaces. The design and operating rules live in
docs/plans/fuzzing.md (adopted from alkhttp's
docs/plans/fuzzing.md; rationale in alkcall's
docs/research/fuzzing.md) — this README is the operational
cheat-sheet.
Layout
fuzz_targets/— nightly-onlyfuzz_target!binaries (thin wrappers).shared/— stable-toolchain library holding the invariant logic; the corpus replay tests run here on plaincargo test.corpus/<target>/— committed seeds (regenerate withpython3 fuzz/gen_fuzz_seeds.py).artifacts/— gitignored crash/oom/timeout artifacts + campaign logs.
Targets
| Target | Drives |
|---|---|
bast_compile |
AlkTypeEngine::compile in both layout modes over attacker-shaped BAST JSON (the whole schema side through one choke point) + validate_bast_doc + build_validator |
data_access |
the hand-rolled decode core (src/data_access.rs): fixed-width kinds, bool strictness, length-prefixed and indirect string/bytes, enums — over raw bytes with attacker-chosen offsets and endianness |
read_opseq |
the stateful SequentialReader (packed read side): op sequences (Next / NextBorrowed / Field / Reset / End) over hostile buffers under the compiled plan — cursor discipline, plan-order walks, the record-count spin bound, ADR-007 reader independence |
layout_build |
the packed write side (LayoutBuilder::build) with adversarial var_sizes over a five-schema menu — position disjointness/bounds, failed-write buffer-untouched contracts, write→read pair round trip |
Running a campaign — always detached
Agent sessions must never run fuzzing in the foreground (an OOM in a target can take down the session host; see docs/plans/fuzzing.md §2). Use the detached runner:
fuzz/run-detached.sh bast_compile
# poll:
tail -n 50 fuzz/artifacts/bast_compile-*.log
ls fuzz/artifacts/bast_compile/
pgrep -f "cargo fuzz run bast_compile"
FUZZ_RUNTIME_SECS=1800 fuzz/run-detached.sh bast_compile for a longer
campaign. The runner pins -fork=1 -rss_limit_mb=2048 -malloc_limit_mb=2048 -timeout=25 and detaches via setsid + nohup.
Corpus replay (the standing fuzz gate)
cargo test --manifest-path fuzz/shared/Cargo.toml
replays every committed seed through the same invariant functions the fuzz targets run — on stable, without nightly, no cargo-fuzz. Part of the release verification checklist (AGENTS.md).
Toolchain
fuzz/rust-toolchain.toml pins nightly (+ llvm-tools-preview) for
this subtree only; the main crate stays stable at MSRV 1.85. cargo fuzz build works from any CWD inside fuzz/ (rustup resolves the
toolchain per directory). Build:
cd fuzz && cargo fuzz build
# or from the repo root — the toolchain file is picked up by path:
cargo fuzz build -D