From 752e36b5267bcff4842c6828790e32f85e9081ba Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Wed, 30 Sep 2026 05:16:11 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20fuzzing=20wave-1=20status=20=E2=80=94?= =?UTF-8?q?=20campaigns=20clean,=20seeds=20count,=20dict=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bast_compile smoke: 543k execs, 10830 edges, coverage still growing at budget end; data_access smoke: 3.5M execs, saturated at 379 edges - both exited 0, empty artifact dirs, oom/timeout/crash 0/0/0 - json.dict: libFuzzer's parser rejects \u escapes and unquoted tails (caught at campaign launch, not by the fuzzer) - plan doc §3/§5/§6/§7 updated with wave-1 results --- docs/plans/fuzzing.md | 65 +++++++++++++++++++++++++++++++++++-------- fuzz/json.dict | 4 +-- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/docs/plans/fuzzing.md b/docs/plans/fuzzing.md index 5afa910..3a7d531 100644 --- a/docs/plans/fuzzing.md +++ b/docs/plans/fuzzing.md @@ -22,9 +22,30 @@ 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:** plan adopted (2026-09-30); implementation not started. The -pre-fuzzing inventory (§6) is verified against the code at 0.3.0. No -`fuzz/` directory exists and no finding has been logged. +**Status:** wave 1 implemented and verified (2026-09-30). The pre-fuzzing +inventory (§6) is verified against the code at 0.3.0. Targets 1–2 and +the full infrastructure are in-tree (commit `ed41d77`); both smoke +campaigns ran clean (10 min detached per target, §5); no findings. + +Progress log: + +- **2026-09-30 — wave 1 landed (commit `ed41d77`).** The `fuzz/` + workspace, 136 committed seeds (38 `bast_compile` + 98 + `data_access`), the detached runner, the corpus-replay gate + (AGENTS.md checklist gains the line), nightly pinned subtree, + explicit root `[workspace]` exclusion, publish-exclude gain, + `json.dict`. `cargo fuzz build` clean; corpus replay 4/4 green; + main crate untouched (569 tests, clippy `-D warnings` clean). One + dict-format fix on the way: libFuzzer's dictionary parser does not + accept `\u` escapes (`"\u0000"` → the `\xAB` form) and needs fully + quoted lines — caught by the campaign launcher, not the fuzzer. +- **2026-09-30 — smoke campaigns clean (see §5).** `data_access` + saturated (pure decode core, the alkcall `chunk_header` profile); + `bast_compile` still discovering coverage at budget end (longer + campaigns keep paying). No crate findings — the §6 candidates + (record-count loops, indirect pairs) held under the parser-level + drives; both remain encoded as wave-2/3 invariants in the stateful + targets. --- @@ -116,8 +137,8 @@ checklist, as the siblings did. | # | Target | Drives | Input style | Status | |---|---|---|---|---| -| 1 | `bast_compile` | `AlkTypeEngine::compile` both modes (via `bast_meta` → `BastDoc` → plans → layout → validator) | raw bytes → serde_json → BAST doc | planned | -| 2 | `data_access` | the hand-rolled decode core (`src/data_access.rs`, read side) | raw `&[u8]` + chosen (offset, endian) | planned | +| 1 | `bast_compile` | `AlkTypeEngine::compile` both modes (via `bast_meta` → `BastDoc` → plans → layout → validator) | raw bytes → serde_json → BAST doc | implemented 2026-09-30 | +| 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 | planned (wave 2) | | 4 | `layout_build` | `LayoutBuilder::build` with adversarial `var_sizes` | `#[derive(Arbitrary)]` map shapes | planned (wave 2) | | 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) | @@ -329,6 +350,24 @@ repo): MSRV, and wasm target are untouched — `cargo fuzz build` must never be a prerequisite for `cargo test`/`clippy`/`build`. +Wave-1 smoke campaign results (2026-09-30, 10 min per target, both +exited 0, artifact dirs empty — no crash/hang/OOM/leak): + +- `bast_compile` — 543k execs at ~1.1k/s (each exec compiles two + engines through the whole fan-out — meta gate, parse, plans, layout + walks — in both modes, so per-exec work is heavy), coverage 10,830 + edges / 25,326 features / 1,293 in-memory corpus entries, **still + growing at budget end** — longer campaigns keep paying. +- `data_access` — 3.5M+ execs at ~7–8k/s, coverage saturated at 379 + edges / 574 features / 37 corpus entries (the pure-decode-core + ceiling is fully enumerated; the alkcall `chunk_header` profile). +- Both exited 0 with empty artifact directories; `oom/timeout/crash: + 0/0/0` on every fork job. +- **Seeds regenerate deterministically:** `python3 + fuzz/gen_fuzz_seeds.py`. +- Toolchain notes live in `fuzz/README.md`; nightly stays confined to + `fuzz/`. + ## 6. Pre-fuzzing candidate findings (confirm or refute) These are pre-fuzzing code-review findings from the 0.3.0 inventory, @@ -376,17 +415,21 @@ confirms or refutes them. 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). +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 +2–3 (targets 3–5), and 4 keeps its boundary corpus entry. ## 7. Sequencing -1. **Wave 1** — `cargo fuzz init`, infra (`workspace` exclude, - toolchain pin, runner, seed generator, README, `.gitignore`), - targets 1–2 + corpora + corpus replay + AGENTS.md gate + smoke - campaigns (10 min per target, detached). +1. ✅ **Wave 1 (2026-09-30, commit `ed41d77`)** — infra (`workspace` + exclude, toolchain pin, runner, seed generator, README, + `.gitignore`) + targets 1–2 + corpora (136 seeds) + corpus replay + + AGENTS.md gate + smoke campaigns (clean, see §5). 2. **Wave 2** — targets 3–4 (stateful `read_opseq`, `layout_build`) + seeds + smoke campaigns. Add regression fixtures for anything - wave 1 surfaced first. + wave 1 surfaced first (nothing so far). 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. diff --git a/fuzz/json.dict b/fuzz/json.dict index 33e1891..9e67eab 100644 --- a/fuzz/json.dict +++ b/fuzz/json.dict @@ -56,7 +56,7 @@ "{}}]" "[]" "[[" -"]] +"]]" "{\"$defs\":{}}" "{\"kind\":\"struct\",\"fields\":[]}" "\"$ref\":\"#/$defs/" @@ -81,5 +81,5 @@ "\"\"" # Strings that stress the parser "AAAABBBBCCCCDDDD" -"\u0000" +"\x00" "\\" \ No newline at end of file