| 1 |
# Seed corpora |
| 2 |
|
| 3 |
Hand-written and captured starting inputs, one directory per fuzz target. |
| 4 |
These are committed; `corpus/` is not. |
| 5 |
|
| 6 |
The split follows `astra-soak-overview`, which calls a minimized corpus |
| 7 |
"accumulated compute, not a build artifact": |
| 8 |
|
| 9 |
- **These seeds are human intent.** Most are real terminal traffic, captured |
| 10 |
under `script(1)` from the twelve vtebench benchmarks and from eight |
| 11 |
ordinary programs (`ls --color -R`, `top -b`, a coloured |
| 12 |
`git log --graph`, helix, nano, btop, less, tmux), sliced at escape |
| 13 |
boundaries. The rest is one file per protocol shape worth reaching in the |
| 14 |
first second rather than the first hour: each string state, the scroll |
| 15 |
region, the alt screen, wide characters at the right edge, truncated UTF-8, |
| 16 |
and the queries a program waits on an answer for. |
| 17 |
- **`corpus/` is machine output and lives on astra**, under the soak runner's |
| 18 |
persistent directory. Minimize with `cargo +nightly fuzz cmin vt` and commit |
| 19 |
it once it represents real soak hours, not before. |
| 20 |
|
| 21 |
## Input format |
| 22 |
|
| 23 |
The first two bytes of every input choose the grid: `1 + b[0] % 200` columns |
| 24 |
and `1 + b[1] % 60` rows. Everything after them is the byte stream. The |
| 25 |
captured seeds carry a 100x30 header, so they are a capture with two bytes in |
| 26 |
front rather than a different format. One seed picks a 1x1 grid, which is the |
| 27 |
degenerate case every piece of the ring arithmetic has to survive. |
| 28 |
|
| 29 |
Run against these on a machine with no corpus: |
| 30 |
|
| 31 |
mkdir -p fuzz/corpus/vt |
| 32 |
cargo +nightly fuzz run vt fuzz/corpus/vt fuzz/seeds/vt |
| 33 |
|
| 34 |
The `mkdir` is needed once. `cargo fuzz` creates the default corpus directory |
| 35 |
for you only when you name no directories at all; pass them explicitly and |
| 36 |
libFuzzer requires every one to exist already. |
| 37 |
|
| 38 |
**Name the corpus directory first and this one second.** libFuzzer writes new |
| 39 |
inputs into whichever directory it is given first and treats the rest as |
| 40 |
read-only. Passing `fuzz/seeds/vt` alone dumps thousands of machine-generated |
| 41 |
files in here and buries the hand-written ones, which is exactly the split this |
| 42 |
directory exists to keep. |
| 43 |
|
| 44 |
## Crash seeds |
| 45 |
|
| 46 |
An input that once found a bug stays here forever, and also becomes a file |
| 47 |
under `fuzz/regressions/`, which `tests/regressions.rs` replays on stable. |
| 48 |
|
| 49 |
- `63-decstbm-inverted`. `ESC [ 20 ; 3 r` sets a scroll region whose top is |
| 50 |
below its bottom, and `scroll_up_in_region` computes `bottom - top + 1`: an |
| 51 |
underflow, so a panic in debug and a region of about 65,000 rows in release, |
| 52 |
feeding a row index off the end of the ring into the unchecked store in |
| 53 |
`place_char`. |
| 54 |
- `104-delete-lines-whole-region`. `ESC [ 9999 M` on the top row of the |
| 55 |
region. DL clamps its count to the region size, and a copy loop that computes |
| 56 |
`scroll_bottom - n` underflows once the delete covers the whole region from |
| 57 |
its first row. |
| 58 |
- `106-pad-then-narrow-write`. A wide character with one column left leaves a |
| 59 |
pad at the right edge. Reading that pad as the second half of a pair makes a |
| 60 |
narrow write over it blank the cell two columns back, which is a real spacer, |
| 61 |
leaving its lead on screen as half a character. No panic, so only the |
| 62 |
wide-pair invariant catches it. |
| 63 |
|