max / shop
| 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 | |
| 29 | |
| 30 | use fuzz_target; |
| 31 | |
| 32 | fuzz_target! |
| 33 | check_bytes; |
| 34 | ; |
| 35 |