From ea17f8091939c7687bd51585f4747a6490999ab8 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 12 Jan 2020 14:03:52 +0100 Subject: [PATCH] Add fuzzing of TinyVec as well --- fuzz/Cargo.toml | 2 +- fuzz/src/bin/tinyvec.rs | 96 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 fuzz/src/bin/tinyvec.rs diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index ef9273b..e73ed6a 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" publish = false [dependencies] -tinyvec = { path = "..", features = ["nightly_slice_partition_dedup"] } +tinyvec = { path = "..", features = ["extern_crate_alloc", "nightly_slice_partition_dedup"] } arbitrary-model-tests = { git = "https://github.com/jakubadamw/arbitrary-model-tests" } honggfuzz = "0.5.45" arbitrary = "0.2.0" diff --git a/fuzz/src/bin/tinyvec.rs b/fuzz/src/bin/tinyvec.rs new file mode 100644 index 0000000..85d240e --- /dev/null +++ b/fuzz/src/bin/tinyvec.rs @@ -0,0 +1,96 @@ +use derive_arbitrary::Arbitrary; +use arbitrary_model_tests::arbitrary_stateful_operations; +use honggfuzz::fuzz; +use std::{fmt::Debug, iter::FromIterator, ops::{RangeBounds, Bound}}; + +use tinyvec::TinyVec; +use tinyvec_fuzz::ArbRange; + +const CAPACITY: usize = 32; + +arbitrary_stateful_operations! { + model = Vec, + tested = TinyVec<[T; CAPACITY]>, + + type_parameters = < + T: Default + Clone + Debug + Eq + Ord, + R: RangeBounds + Clone + Debug, + >, + + methods { + equal { + fn as_mut_slice(&mut self) -> &mut [T]; + fn as_slice(&self) -> &[T]; + fn clear(&mut self); + fn dedup(&mut self); + fn insert(&mut self, index: usize, item: T); + fn is_empty(&self) -> bool; + fn len(&self) -> usize; + fn push(&mut self, item: T); + fn truncate(&mut self, new_len: usize); + } + + equal_with(Vec::from_iter) { + fn drain(&self, range: R) -> impl Iterator; + fn iter(&self) -> impl Iterator; + fn iter_mut(&self) -> impl Iterator; + } + } + + pre { + match self { + Self::insert { index, .. } if index > model.len() => { + // TODO: Should test that these identically panic + return; + } + Self::drain { ref range } => { + // TODO: Should test that these identically panic + let start = match range.start_bound() { + Bound::Included(&n) => n, + Bound::Excluded(&n) => n + 1, + Bound::Unbounded => 0, + }; + let end = match range.end_bound() { + // If it's already usize::max, doesn't really matter about adding 1 + Bound::Included(&n) => n.checked_add(1).unwrap_or(n), + Bound::Excluded(&n) => n, + Bound::Unbounded => model.len(), + }; + if start > end || end > model.len() { + return; + } + } + _ => {} + } + } +} + +const MAX_RING_SIZE: usize = 16_384; + +fn fuzz_cycle(data: &[u8]) -> Result<(), ()> { + use arbitrary::{Arbitrary, FiniteBuffer}; + + let mut ring = FiniteBuffer::new(&data, MAX_RING_SIZE).map_err(|_| ())?; + + let mut model = Vec::::default(); + let mut tested: TinyVec<[u16; 32]> = TinyVec::new(); + + let mut _op_trace = String::new(); + while let Ok(op) = > as Arbitrary>::arbitrary(&mut ring) { + #[cfg(fuzzing_debug)] + _op_trace.push_str(&format!("{}\n", op.to_string())); + op.execute_and_compare(&mut model, &mut tested); + } + + Ok(()) +} + +fn main() -> Result<(), ()> { + better_panic::install(); + + loop { + fuzz!(|data: &[u8]| { + let _ = fuzz_cycle(data); + }); + } +}