Fuzz Fuzz Fuzz (#98)

* more features for fuzzing

* arrayveciter fuzzer + overflow fix

* moar fuzzers and tinyvecdrain change

* cargo fmt

* Self on enums is not stable in 1.36

* 🐞 BUGFIX: ArrayVecIterator::nth_back

* cargo fmt
This commit is contained in:
Soveu
2020-08-02 22:40:13 +02:00
committed by GitHub
parent 9372c2052c
commit 41abf04f28
8 changed files with 314 additions and 62 deletions
+4 -1
View File
@@ -6,8 +6,11 @@ edition = "2018"
publish = false
[dependencies]
tinyvec = { path = "..", features = ["alloc", "nightly_slice_partition_dedup"] }
rutenspitz = "0.2.1"
honggfuzz = "0.5.45"
arbitrary = { version = "0.4.5", features = ["derive"] }
better-panic = "0.2.0"
[dependencies.tinyvec]
path = ".."
features = ["rustc_1_40", "grab_spare_slice", "alloc", "nightly_slice_partition_dedup"]
+1 -5
View File
@@ -1,10 +1,6 @@
use honggfuzz::fuzz;
use std::{
fmt::Debug,
iter::FromIterator,
ops::RangeBounds,
};
use rutenspitz::arbitrary_stateful_operations;
use std::{fmt::Debug, iter::FromIterator, ops::RangeBounds};
use tinyvec::ArrayVec;
use tinyvec_fuzz::ArbRange;
+79
View File
@@ -0,0 +1,79 @@
use honggfuzz::fuzz;
use rutenspitz::arbitrary_stateful_operations;
use std::{convert::TryInto, fmt::Debug};
use tinyvec::{ArrayVec, ArrayVecDrain};
use tinyvec_fuzz::ArbRange;
const CAPACITY: usize = 28;
arbitrary_stateful_operations! {
model = std::vec::Drain<'_, u32>,
tested = ArrayVecDrain<'_, u32>,
methods {
equal {
fn next(&mut self) -> Option<u32>;
fn nth(&mut self, n: usize) -> Option<u32>;
fn next_back(&mut self) -> Option<u32>;
fn nth_back(&mut self, n: usize) -> Option<u32>;
fn size_hint(&self) -> (usize, Option<usize>);
}
}
}
fn xorshift(x: u32) -> u32 {
let x = x ^ (x << 13);
let x = x ^ (x >> 17);
let x = x ^ (x << 5);
return x;
}
fn seed(data: &[u8]) -> u32 {
let mut rng = [1u8; 4];
let len = if data.len() > 4 { 4 } else { data.len() };
rng[..len].copy_from_slice(&data[..len]);
u32::from_ne_bytes(rng)
}
fn rand_arrvec(mut x: u32) -> ArrayVec<[u32; CAPACITY]> {
let mut tested: ArrayVec<[u32; CAPACITY]> = ArrayVec::new();
let len = xorshift(x) as usize % CAPACITY;
tested.set_len(len);
for item in tested.iter_mut() {
x = xorshift(x);
*item = x;
}
return tested;
}
fn fuzz_cycle(data: &[u8]) -> Result<(), ()> {
use arbitrary::{Arbitrary, Unstructured};
let mut ring = Unstructured::new(&data);
let rng = seed(data);
let mut tested = rand_arrvec(rng);
let mut model: Vec<u32> = Vec::from(tested.as_slice());
let mut tested = tested.drain(..);
let mut model = model.drain(..);
while let Ok(op) = op::Op::arbitrary(&mut ring) {
op.execute_and_compare(&mut model, &mut tested);
}
Ok(())
}
fn main() -> Result<(), ()> {
better_panic::install();
loop {
fuzz!(|data: &[u8]| {
let _ = fuzz_cycle(data);
});
}
}
+89
View File
@@ -0,0 +1,89 @@
use honggfuzz::fuzz;
use rutenspitz::{arbitrary_stateful_operations, OutcomePanic};
use std::{convert::TryInto, fmt::Debug};
use tinyvec::{ArrayVec, ArrayVecIterator};
use tinyvec_fuzz::ArbRange;
const CAPACITY: usize = 28;
arbitrary_stateful_operations! {
model = std::vec::IntoIter<u32>,
tested = ArrayVecIterator<[u32; CAPACITY]>,
methods {
equal {
fn next(&mut self) -> Option<u32>;
fn nth(&mut self, n: usize) -> Option<u32>;
fn next_back(&mut self) -> Option<u32>;
fn nth_back(&mut self, n: usize) -> Option<u32>;
fn size_hint(&self) -> (usize, Option<usize>);
}
}
}
fn xorshift(x: u32) -> u32 {
let x = x ^ (x << 13);
let x = x ^ (x >> 17);
let x = x ^ (x << 5);
return x;
}
fn seed(data: &[u8]) -> u32 {
let mut rng = [1u8; 4];
let len = if data.len() > 4 { 4 } else { data.len() };
rng[..len].copy_from_slice(&data[..len]);
u32::from_ne_bytes(rng)
}
fn rand_arrvec(mut x: u32) -> ArrayVec<[u32; CAPACITY]> {
let mut tested: ArrayVec<[u32; CAPACITY]> = ArrayVec::new();
let len = xorshift(x) as usize % CAPACITY;
tested.set_len(len);
for item in tested.iter_mut() {
x = xorshift(x);
*item = x;
}
return tested;
}
fn fuzz_cycle(data: &[u8]) -> Result<(), ()> {
use arbitrary::{Arbitrary, Unstructured};
let mut ring = Unstructured::new(&data);
let rng = seed(data);
let tested = rand_arrvec(rng);
let model: Vec<u32> = Vec::from(tested.as_slice());
let mut tested = tested.into_iter();
let mut model = model.into_iter();
while let Ok(op) = op::Op::arbitrary(&mut ring) {
#[cfg(fuzzing_debug)]
eprintln!("{:?}", op);
op.execute_and_compare(&mut model, &mut tested);
}
Ok(())
}
fn main() -> Result<(), ()> {
//better_panic::install();
std::panic::set_hook(Box::new(|panic_info| {
if let Some(outpanic) =
panic_info.payload().downcast_ref::<rutenspitz::OutcomePanic>()
{
eprintln!("{}", outpanic.0);
std::process::abort();
}
}));
loop {
fuzz!(|data: &[u8]| {
let _ = fuzz_cycle(data);
});
}
}
+1 -5
View File
@@ -1,10 +1,6 @@
use honggfuzz::fuzz;
use std::{
fmt::Debug,
iter::FromIterator,
ops::RangeBounds,
};
use rutenspitz::arbitrary_stateful_operations;
use std::{fmt::Debug, iter::FromIterator, ops::RangeBounds};
use tinyvec::TinyVec;
use tinyvec_fuzz::ArbRange;
+78
View File
@@ -0,0 +1,78 @@
use honggfuzz::fuzz;
use rutenspitz::arbitrary_stateful_operations;
use std::{convert::TryInto, fmt::Debug};
use tinyvec::{TinyVec, TinyVecDrain};
use tinyvec_fuzz::ArbRange;
const CAPACITY: usize = 28;
arbitrary_stateful_operations! {
model = std::vec::Drain<'_, u32>,
tested = TinyVecDrain<'_, [u32; CAPACITY]>,
methods {
equal {
fn next(&mut self) -> Option<u32>;
fn nth(&mut self, n: usize) -> Option<u32>;
fn next_back(&mut self) -> Option<u32>;
fn nth_back(&mut self, n: usize) -> Option<u32>;
fn size_hint(&self) -> (usize, Option<usize>);
}
}
}
fn xorshift(x: u32) -> u32 {
let x = x ^ (x << 13);
let x = x ^ (x >> 17);
let x = x ^ (x << 5);
return x;
}
fn seed(data: &[u8]) -> u32 {
let mut rng = [1u8; 4];
let len = if data.len() > 4 { 4 } else { data.len() };
rng[..len].copy_from_slice(&data[..len]);
u32::from_ne_bytes(rng)
}
fn rand_tinyvec(mut x: u32) -> TinyVec<[u32; CAPACITY]> {
let mut tested: TinyVec<[u32; CAPACITY]> = Default::default();
let len = xorshift(x) as u8; /* Effectively modulo 256 */
for _ in 0..len {
x = xorshift(x);
tested.push(x);
}
return tested;
}
fn fuzz_cycle(data: &[u8]) -> Result<(), ()> {
use arbitrary::{Arbitrary, Unstructured};
let mut ring = Unstructured::new(&data);
let rng = seed(data);
let mut tested = rand_tinyvec(rng);
let mut model: Vec<u32> = Vec::from(tested.as_slice());
let mut tested = tested.drain(..);
let mut model = model.drain(..);
while let Ok(op) = op::Op::arbitrary(&mut ring) {
op.execute_and_compare(&mut model, &mut tested);
}
Ok(())
}
fn main() -> Result<(), ()> {
better_panic::install();
loop {
fuzz!(|data: &[u8]| {
let _ = fuzz_cycle(data);
});
}
}
+12 -7
View File
@@ -1171,15 +1171,20 @@ impl<A: Array> DoubleEndedIterator for ArrayVecIterator<A> {
#[cfg(feature = "rustc_1_40")]
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let slice =
&mut self.data.as_slice_mut()[self.base as usize..self.tail as usize];
let n = slice.len().checked_sub(n + 1)?;
let item = &mut slice[n];
let base = self.base as usize;
let tail = self.tail as usize;
let slice = &mut self.data.as_slice_mut()[base..tail];
let n = n.saturating_add(1);
/* n is in [0..self.tail - self.base] range, so in u16 range */
self.tail = self.base + n as u16;
if let Some(n) = slice.len().checked_sub(n) {
let item = &mut slice[n];
/* n is in [0..self.tail - self.base] range, so in u16 range */
self.tail = self.base + n as u16;
return Some(take(item));
}
return Some(take(item));
self.tail = self.base;
return None;
}
}
+50 -44
View File
@@ -2,7 +2,7 @@
use super::*;
use alloc::vec::Vec;
use alloc::vec::{self, Vec};
/// Helper to make a `TinyVec`.
///
@@ -423,33 +423,9 @@ impl<A: Array> TinyVec<A> {
&mut self,
range: R,
) -> TinyVecDrain<'_, A> {
use core::ops::Bound;
let start = match range.start_bound() {
Bound::Included(x) => *x,
Bound::Excluded(x) => x + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(x) => x + 1,
Bound::Excluded(x) => *x,
Bound::Unbounded => self.len(),
};
assert!(
start <= end,
"TinyVec::drain> Illegal range, {} to {}",
start,
end
);
assert!(
end <= self.len(),
"TinyVec::drain> Range ends at {} but length is only {}!",
end,
self.len()
);
TinyVecDrain {
parent: self,
target_index: start,
target_count: end - start,
match self {
TinyVec::Inline(i) => TinyVecDrain::Inline(i.drain(range)),
TinyVec::Heap(h) => TinyVecDrain::Heap(h.drain(range)),
}
}
@@ -855,29 +831,59 @@ impl<A: Array> TinyVec<A> {
/// Draining iterator for `TinyVecDrain`
///
/// See [`TinyVecDrain::drain`](TinyVecDrain::<A>::drain)
pub struct TinyVecDrain<'p, A: Array> {
parent: &'p mut TinyVec<A>,
target_index: usize,
target_count: usize,
pub enum TinyVecDrain<'p, A: Array> {
#[allow(missing_docs)]
Inline(ArrayVecDrain<'p, A::Item>),
#[allow(missing_docs)]
Heap(vec::Drain<'p, A::Item>),
}
impl<'p, A: Array> FusedIterator for TinyVecDrain<'p, A> {}
impl<'p, A: Array> Iterator for TinyVecDrain<'p, A> {
type Item = A::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.target_count > 0 {
let out = self.parent.remove(self.target_index);
self.target_count -= 1;
Some(out)
} else {
None
match self {
TinyVecDrain::Inline(i) => i.next(),
TinyVecDrain::Heap(h) => h.next(),
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
match self {
TinyVecDrain::Inline(i) => i.nth(n),
TinyVecDrain::Heap(h) => h.nth(n),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
TinyVecDrain::Inline(i) => i.size_hint(),
TinyVecDrain::Heap(h) => h.size_hint(),
}
}
fn for_each<F: FnMut(Self::Item)>(self, f: F) {
match self {
TinyVecDrain::Inline(i) => i.for_each(f),
TinyVecDrain::Heap(h) => h.for_each(f),
}
}
}
impl<'p, A: Array> Drop for TinyVecDrain<'p, A> {
#[inline]
fn drop(&mut self) {
for _ in self {}
impl<'p, A: Array> DoubleEndedIterator for TinyVecDrain<'p, A> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
TinyVecDrain::Inline(i) => i.next_back(),
TinyVecDrain::Heap(h) => h.next_back(),
}
}
#[cfg(feature = "rustc_1_40")]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
match self {
TinyVecDrain::Inline(i) => i.nth_back(n),
TinyVecDrain::Heap(h) => h.nth_back(n),
}
}
}