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