Parser and graphics fuzz workspace
September 11, 2026 ยท View on GitHub
This standalone cargo-fuzz workspace exercises four external-input seams
without adding fuzz-only dependencies to the release workspace:
parser_dispatch: compares whole-buffer, byte-at-a-time, and deterministic chunk dispatch throughOdyParser, then checks parser recovery with a sentinel.terminal_stream: compares observableTerminalstate across the same feed schedules, with bounded scrollback and graphics storage, then checks RIS reset and sentinel output.kitty_graphics: routes one bounded Kitty APC throughTerminal, keeps named transports disabled, and checks image-store, placement, raw-command, and response bounds.sixel_decode: calls the public Sixel decoder with bounded input and checks dimensions, checked pixel arithmetic, and RGBA length.
The workspace owns its Cargo workspace boundary and lockfile. It pins
libfuzzer-sys to 0.4.13, cargo-fuzz commands to 0.13.2, and Rust to
nightly-2026-07-15. The dated nightly resolved on Linux x86_64 to
rustc 1.99.0-nightly (da80ed070 2026-07-14). The normal project MSRV remains
Rust 1.96.
Root dependency changes must also synchronize this workspace's lockfile. Run
cargo check --manifest-path fuzz/parser_graphics/Cargo.toml --locked --bins
from the repository root to match the blocking Linux CI API check. This stable
compile check does not run fuzzing or replace the nightly campaign below.
Tool setup and structural checks
Install the command at the documented version:
cargo install cargo-fuzz --version 0.13.2 --locked
cargo fuzz --version
Run the structural checks from this directory:
cargo +nightly-2026-07-15 fuzz check
cargo +nightly-2026-07-15 fuzz build parser_dispatch
cargo +nightly-2026-07-15 fuzz build terminal_stream
cargo +nightly-2026-07-15 fuzz build kitty_graphics
cargo +nightly-2026-07-15 fuzz build sixel_decode
Bounded local runs
Create the ignored artifact directories before a run:
mkdir -p artifacts/parser_dispatch artifacts/terminal_stream
mkdir -p artifacts/kitty_graphics artifacts/sixel_decode
Run one target and one worker at a time. Each command has both a shell deadline and libFuzzer time, memory, per-input, and input-length limits. The surrounding job must also enforce the repository's CPU and memory limits; do not run these commands on a host where those limits cannot be established.
CARGO_BUILD_JOBS=4 RUST_TEST_THREADS=1 timeout --kill-after=15s 45s cargo +nightly-2026-07-15 fuzz run parser_dispatch corpus/parser_dispatch -- -max_total_time=30 -timeout=5 -rss_limit_mb=8192 -workers=1 -jobs=1 -max_len=65536 -dict=dictionaries/parser_dispatch.dict -artifact_prefix=artifacts/parser_dispatch/
CARGO_BUILD_JOBS=4 RUST_TEST_THREADS=1 timeout --kill-after=15s 45s cargo +nightly-2026-07-15 fuzz run terminal_stream corpus/terminal_stream -- -max_total_time=30 -timeout=5 -rss_limit_mb=8192 -workers=1 -jobs=1 -max_len=65536 -dict=dictionaries/terminal_stream.dict -artifact_prefix=artifacts/terminal_stream/
CARGO_BUILD_JOBS=4 RUST_TEST_THREADS=1 timeout --kill-after=15s 45s cargo +nightly-2026-07-15 fuzz run kitty_graphics corpus/kitty_graphics -- -max_total_time=30 -timeout=8 -rss_limit_mb=8192 -workers=1 -jobs=1 -max_len=2097152 -dict=dictionaries/kitty_graphics.dict -artifact_prefix=artifacts/kitty_graphics/
CARGO_BUILD_JOBS=4 RUST_TEST_THREADS=1 timeout --kill-after=15s 45s cargo +nightly-2026-07-15 fuzz run sixel_decode corpus/sixel_decode -- -max_total_time=30 -timeout=8 -rss_limit_mb=8192 -workers=1 -jobs=1 -max_len=1048576 -dict=dictionaries/sixel_decode.dict -artifact_prefix=artifacts/sixel_decode/
An input is also clipped inside each target. The command-line limits are not the sole resource boundary.
The scheduled Linux x86_64 smoke uses
.github/scripts/run-coverage-fuzz.sh, which establishes the repository's
transient cgroup limits before running the same four targets sequentially. The
workflow in .github/workflows/coverage-fuzz.yml retains logs, the evolved
corpora, and crash artifacts for 14 days. An unavailable cgroup is a failed
run, not an unbounded fallback.
Corpus and crash handling
corpus.toml records the origin and digest of every retained seed. All seeds
are repository literals or synthetic protocol examples. Private transcripts,
images, settings, paths, and host-derived inputs are prohibited. Newly
generated hash-named corpus entries and all artifacts remain ignored until
manual inspection confirms that they are public-safe.
Preserve a failure artifact and reproduce it with the exact target and pinned toolchain. Minimize it before any closure:
cargo +nightly-2026-07-15 fuzz tmin TARGET artifacts/TARGET/ARTIFACT
After minimization:
- Inspect the bytes for private or host-derived content.
- Reproduce the failure with the minimized artifact.
- Add a focused ordinary test in
tests/fuzz_regressions_parser_graphics.rsand a synthetic fixture intests/fixtures/fuzz/parser_graphics/. - Confirm the ordinary test fails before the correction and passes after it.
- Add a sanitized minimized seed to
corpus/TARGET/and record its digest and origin incorpus.toml.
No crash is closed solely because a corpus entry stops reproducing. Corpus minimization may be run only after retained seeds and artifacts are backed up:
cargo +nightly-2026-07-15 fuzz cmin TARGET corpus/TARGET
Platform scope
These cargo-fuzz commands are supported on Linux and macOS hosts with the
pinned nightly. They are unsupported on Windows. Windows execution must not be
inferred from Linux or macOS results; windows-latest remains a separate
project gate. The stable regression fixture for named Kitty transports includes
a synthetic Windows-style path and executes through the ordinary cross-platform
test suite without accessing that path.