docs: fuzzing wave-3 status — release-budget campaigns, W3-1/2/3 findings, all five targets in-tree

§Status now covers waves 1-3. §5 gains the release-budget numbers
(bast_compile 818k execs still growing; data_access 11.3M execs with
value-profile lifting the saturated edge count 379 -> 684;
read_opseq/layout_build 63k execs each with the stateful search
active through budget; validate_pair 37k execs clean after the fixes).
§3 target-5 marked implemented; §4 records the 48-seed menu; §6
gains candidate 8 (the W3-3 aligned maxLength reservation bug,
confirmed+fixed) and rewrites the evidence summary; §7 wave 3 is
checked off — corpus replay 30/30 stands as the gate.

Verification: cargo doc clean; 573 main-crate tests + 30 replay tests
green; clippy -D warnings clean (crate + shared).
This commit is contained in:
glm-5.3-flash committed 2026-09-30 08:55:30 +00:00
1 parent a0dd3d2de4
commit f809f6ca7e
1 file changed
+133 -18
+133 -18
View File
@@ -22,16 +22,71 @@ pairs) — exactly the shapes where example tests miss off-by-one bugs.
The crate is fully synchronous, so targets are simpler than
alkcall/alkhttp's (no current-thread runtime shims anywhere).
**Status:** waves 1–2 implemented and verified (2026-09-30). The
**Status:** waves 1–3 implemented and verified (2026-09-30). The
pre-fuzzing inventory (§6) is verified against the code at 0.3.0.
Targets 1–4 and the full infrastructure are in-tree (commits `ed41d77`,
wave 1; wave 2); wave-1 smoke campaigns ran clean (§5); the wave-2
`read_opseq` campaign surfaced one real packing bug on its first
semantic fixture — the fixed-stride array window bounds check
(§6 candidate 6) — fixed same-day with a regression test.
All five targets and the full infrastructure are in-tree (commits
`ed41d77`, wave 1; `16b9023`, wave 2; `aef8d9f` + findings commits,
wave 3); the smoke campaigns ran clean (§5); the release-budget
campaigns across all five targets are complete (§5) — two targets
surfaced real findings: the wave-2 `read_opseq` packing bug (§6
candidate 6, fixed same-day) and three wave-3 `validate_pair`
findings (W3-1 harness pin, W3-2 upstream serde_json pin, W3-3 a real
engine bug — read_field/write_field misread aligned maxLength
reservations — fixed same-day with regression tests).
Progress log:
- **2026-09-30 — wave 3 landed.** Target 5 (`validate_pair`): the
two-input harness (10-lane schema menu incl. a raw-JSON-bytes lane
fused with the buffer), 48 committed seeds, decode-pin tests, and
the §3 target-5 invariants (mode agreement incl. the documented
aligned-rejection taxonomy, the materialize⇄validate_bytes verdict
lattice with verbatim error propagation, unknown-path echo,
non-finite-float Access pin, enum-Validation pin, record spin
bound). Pre-campaign hand-drives all held. **Release-budget
campaigns (§5):** 45–46 min across all five targets. bast_compile
818k execs / 19,894 edges (still growing at budget end);
data_access 11.3M execs / 684 edges (a value-profile run lifted the
saturated corpus from 379 to 684 edges); read_opseq 63k execs /
17,519 edges; layout_build 63k execs / 17,659 edges; validate_pair
37k execs / 10,850 edges. **Finding W3-1 (harness invariant
corrected — the fuzzer fired an over-assertion):** the harness
claimed validate_bytes Ok ⇒ every offset-map leaf's range.end ≤
buffer.len() — false for offset-indirect entries, whose pair points
absolutely into the buffer while a maxLength window may dwarf the
validated buffer; the wave-1 data_access bounds partition is the
real contract. Fixed the invariant, pinned the artifact bytes as
seed-044 + a named regression test (commit `9ca9922`).
**Finding W3-2 (upstream, pinned with slack — no alktype bug):**
serde_json's non-`float_roundtrip` parser drifts one ulp when
re-parsing its own emitted shortest repr of adversarial f64 values
(probe: 0x5bffffffffffffff emits 1.4536774485912136e+135 and
parses back one ulp low; std's parser and ryu's own float parse are
exact — the concise reparse is the drift). The harness replaced
bare `Value` equality with a one-ulp structural comparison; the
artifact bytes are seed-047 (commits `a8e955c`/`b7ead99`).
**Finding W3-3 (real engine bug — fixed, commit `a0dd3d2`):**
`AlkTypeEngine::read_field`/`write_field` treated an aligned
`maxLength` reservation (ADR-003 strategy 2, `VARCHAR(N)`: raw
zero-padded window, NUL-trimmed on read — exactly what the
materializer and `validate_bytes` implement) as length-prefixed,
parsing the window's first four raw bytes as a u32 length. Every
aligned schema declaring `maxLength` broke the
validate_bytes⇒read_field lattice whenever the reservation's first
bytes looked like a large prefix (validate Ok, read_field Access
with bogus bounds; write_field wrote prefix+data into a raw
window). Third crash artifact (W3-1's shape family: the campaign
re-found the disagreement space after W3-1's invariant was
corrected). Fix: `VariableEncoding` gains `MaxLengthReserved`
(additive variant, ADR-003 strategy 2); `OffsetMap::compute`
records it for maxLength fields with the default encoding
(`maxLength`+`offset-indirect` stays `OffsetIndirect`, preserving
W3-1's combination semantics); `read_field`/`write_field` dispatch
through new `data_access::read_reservation{,_string}/
write_reservation` (single source of truth with the materializer);
three engine regression tests + the W3-1/W3-2 artifacts as
committed corpus seeds. Post-fix restart: 30-min validate_pair
campaign clean to budget end (37k execs, 10,850 edges, exit 0).
- **2026-09-30 — wave 2 landed.** Targets 3 (`read_opseq`) and 4
(`layout_build`) with 73 committed seeds (58 + 15), decode-pin tests
for the arbitrary 1.4.2 derive encoding, and the plan §6 candidate-1
@@ -172,7 +227,7 @@ checklist, as the siblings did.
| 2 | `data_access` | the hand-rolled decode core (`src/data_access.rs`, read + write side) | raw `&[u8]` + chosen (offset, endian) | implemented 2026-09-30 |
| 3 | `read_opseq` | stateful `SequentialReader` op sequences over hostile bytes under a fixed plan | `#[derive(Arbitrary)]` op enum | implemented 2026-09-30 |
| 4 | `layout_build` | `LayoutBuilder::build` with adversarial `var_sizes` | `#[derive(Arbitrary)]` map shapes | implemented 2026-09-30 |
| 5 | `validate_pair` | two-input structured: compile a schema once per exec, hammer hostile bytes through `validate_bytes`/`read_field`/`materialize` | `#[derive(Arbitrary)]` (doc, bytes) pair | planned (wave 3) |
| 5 | `validate_pair` | two-input structured: compile a schema once per exec, hammer hostile bytes through `validate_bytes`/`read_field`/`materialize` | `#[derive(Arbitrary)]` (doc, bytes) pair | implemented 2026-09-30 |
### Target 1 — `bast_compile` (the whole schema side, one choke point)
@@ -355,9 +410,11 @@ grown corpora and artifacts gitignored. Seed menus:
1.4.2 derive layout and *pinned by decode tests* (both targets carry
a `decode_lands_on_the_intended_variants` replay test, the alkhttp
target-4 pattern).
- `validate_pair` (wave 3): hostile-schema/valid-bytes,
valid-schema/hostile-bytes, valid/valid — plus the §6 candidate
shapes as pinned reproducers.
- `validate_pair` (wave 3, **done 2026-09-30**): hostile-schema/
valid-bytes, valid-schema/hostile-bytes, valid/valid — plus the §6
candidate shapes as pinned reproducers. 48 committed seeds incl.
the W3-1/W3-2 artifact bytes, the aligned maxLength fixtures, and
the mode-agreement pins (ADR-006/ADR-008 lanes).
Stateful `Arbitrary` seeds are hand-encoded against the `arbitrary`
1.4.x derive layout with per-element keep-going bytes, pinned by
@@ -386,6 +443,34 @@ repo):
MSRV, and wasm target are untouched — `cargo fuzz build` must never
be a prerequisite for `cargo test`/`clippy`/`build`.
Release-budget campaign results (2026-09-30, 45–46 min per target,
§5 policy, detached, `-use_value_profile=1`, `-dict=json.dict` on the
JSON lanes): all five exited 0.
- `bast_compile` — 818k execs at ~300–500/s (2,756 s), coverage
19,894 edges / 86,455 features / 4,439 in-memory corpus entries,
**still growing at budget end** (2× the wave-1 45-min smoke edge
count). Longest campaigns keep paying on the schema side.
- `data_access` — 11.3M execs at ~3.7–4.7k/s (2,761 s), coverage 684
edges / 6,208 features — value-profile lifted the "saturated" 379
edges to 684 (the wave-1 ceiling was the no-profile ceiling).
- `read_opseq` — 63k execs at ~23/s (2,737 s), coverage 17,519 edges /
65,059 features / 1,668 entries; the stateful search kept adding
features across the full budget (assertion-throughput-bound).
- `layout_build` — 63k execs at ~23/s (2,751 s), coverage 17,659
edges / 71,477 features / 1,873 entries; write-side contracts held.
- `validate_pair` — three crashes over two runs before and one clean
run after the W3-1/W3-2/W3-3 fixes (final post-fix campaign 30 min):
37k execs (final 1,820 s run), coverage 10,850 edges / 38,364
features / 1,544 entries, `oom/timeout/crash: 0/0/0` at budget end.
The two-input harness is the highest-yield target in the crate: 1
real engine bug + 2 pinned contracts in its first campaigns.
- Artifact totals: the three `validate_pair` crash artifacts are all
pinned as committed seeds/regression tests (W3-1 `seed-044`, W3-2
`seed-047`, W3-3 reproduced by the aligned maxLength fixtures);
`bast_compile`/`data_access`/`read_opseq`/`layout_build` artifacts
empty. No OOM, timeout, or leak on any fork job of any target.
Wave-2 smoke campaign results (2026-09-30, 10 min per target, §5
policy, detached):
@@ -497,17 +582,39 @@ confirms or refutes them.
declaration rejected in packed mode, that is a schema-gate change
with the mode-agreement invariant to re-verify.
8. **Aligned `maxLength` reservation read paths disagreed —
CONFIRMED as a real engine bug and FIXED (wave 3, finding W3-3,
found by the `validate_pair` campaign).** The materializer and
`validate_bytes` implement ADR-003 strategy 2 correctly (raw
zero-padded window, NUL-trimmed), but `AlkTypeEngine::read_field`
dispatched every aligned String/Bytes leaf through the
length-prefixed `data_access::read_string`/`read_bytes` — parsing
the reservation window's first four raw bytes as a u32 length —
and `write_field` wrote prefix+data into the raw window. Any
aligned schema declaring `maxLength` whose first reservation bytes
looked like a large prefix broke the validate_bytes ⇒ read_field
lattice (validate Ok, read Access with bogus bounds). Fixed by
recording the strategy in `LeafMeta`'s encoding
(`VariableEncoding::MaxLengthReserved`, additive variant) and
dispatching read/write through new
`data_access::read_reservation{,_string}`/`write_reservation`
sharing the materializer's exact semantics. Regression tests in
`src/engine.rs` + `data_access.rs`; the W3-1 artifact bytes are
the committed reproducer (`seed-044`).
None of these rises to the alkcall §6.2 / alkhttp FWD-20 class; they
are boundary-confirmations, which is exactly the expected profile of
this crate (§1 honest caveat). Smoke-campaign evidence so far: no
panics or OOM/timeouts on any of the 383k+ combined execs (2026-09-30,
§5); candidates 1, 2, and 4 held under the parser-level drives —
candidates 1 and 2 get their explicit stateful assertions in waves
this crate (§1 honest caveat). Smoke-campaign evidence: no panics or
OOM/timeouts on any of the 383k+ wave-1/2 combined execs; the
release-budget campaigns added 12.3M+ execs with the W3 findings
above. Candidates 1, 2, and 4 held under the parser-level drives —
candidates 1 and 2 got their explicit stateful assertions in waves
2–3 (targets 3–5), and 4 keeps its boundary corpus entry. Candidate 3
(duplicate first-wins) is pinned by the wave-2 `layout_build` index
assertions and the existing crate tests; candidate 6 was confirmed as
a genuine bug and fixed in wave 2; candidate 7 is pinned with an open
design question.
design question; candidate 8 was confirmed as a genuine bug and fixed
in wave 3.
## 7. Sequencing
@@ -520,9 +627,17 @@ design question.
One real bug found and fixed first-session (`plan_read_array`
bounds check, §6 candidate 6); packed-mode offset-indirect pinned
as a documented no-op (§6 candidate 7).
3. **Wave 3** — target 5 `validate_pair` (the two-input structured
harness) + long (45 min) release-budget campaigns across all
targets; merge any curated inputs into seeds deliberately.
3. ✅ **Wave 3 (2026-09-30)** — target 5 `validate_pair` (the
two-input structured harness) + 48 seeds + decode-pin tests +
45-min release-budget campaigns across all five targets. Three
findings: W3-1 (harness over-assertion corrected + pinned), W3-2
(upstream serde_json one-ulp f64 parse drift pinned with slack),
W3-3 (real engine bug — aligned maxLength reservation misread by
`read_field`/`write_field` — fixed with `VariableEncoding::
MaxLengthReserved` + `data_access::read_reservation*`/
`write_reservation`, commit `a0dd3d2`). Post-fix
validate_pair campaign clean to budget end. Fuzzing complete per
§2 scope: corpus replay 30/30 is the standing gate.
4. Everything else inherited verbatim: no hosted CI, OSS-Fuzz out,
no Actions/workflow files anywhere in the repo (alkcall §7.9).