mirror of
https://github.com/openharmony/third_party_rust_tinyvec.git
synced 2026-07-21 01:35:22 -04:00
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:
+4
-1
@@ -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,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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user