Skip to main content

max / shop

1.5 KB · 35 lines History Blame Raw
1 //! Structured fuzz over the escape-sequence path, from PTY bytes to the grid.
2 //!
3 //! The failure this hunts is memory corruption in code that renders untrusted
4 //! bytes: everything a program prints reaches `Grid::place_char`, which writes
5 //! through `get_unchecked_mut` on the strength of invariants that the CSI
6 //! cursor, DECSTBM, scroll and resize paths maintain from those same bytes.
7 //!
8 //! It is registered as the `shop-vt` soak target and it does drive `shop-vt`,
9 //! but the fuzz crate lives beside `shop-grid` on purpose. `shop-vt` contains
10 //! no `unsafe` at all, so a target that fed it a no-op `Perform` could only
11 //! ever assert that it does not panic, which is the weakest thing a target can
12 //! say and reads as a defended path forever. The unchecked stores are one crate
13 //! downstream, and this is what puts them under the sanitizer.
14 //!
15 //! ## The oracle lives in the crate, not here
16 //!
17 //! Everything asserted is `shop_grid::oracle::check_bytes`. The committed
18 //! regression replay in `tests/regressions.rs` calls the same function on
19 //! stable, so a crash found here becomes a unit test by copying one file, and
20 //! neither side can drift into checking less than the other.
21 //!
22 //! ## Input shape
23 //!
24 //! The first two bytes choose the grid size, everything after them is the byte
25 //! stream. Committed seeds carry that header, so a seed is a capture with two
26 //! bytes in front of it rather than a different format.
27
28 #![no_main]
29
30 use libfuzzer_sys::fuzz_target;
31
32 fuzz_target!(|data: &[u8]| {
33 shop_grid::oracle::check_bytes(data);
34 });
35