mirror of
https://github.com/openharmony/third_party_rust_tinyvec.git
synced 2026-07-21 01:35:22 -04:00
SliceVec fuzzer + overflow fix on usize::MAX ranges (#99)
* add slicevec fuzzer * prevent overflow on range calculation
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
use honggfuzz::fuzz;
|
||||
use rutenspitz::arbitrary_stateful_operations;
|
||||
use std::{fmt::Debug, iter::FromIterator, ops::RangeBounds};
|
||||
|
||||
use tinyvec::SliceVec;
|
||||
use tinyvec_fuzz::ArbRange;
|
||||
|
||||
arbitrary_stateful_operations! {
|
||||
model = Vec<T>,
|
||||
tested = SliceVec<'_, T>,
|
||||
|
||||
type_parameters = <
|
||||
T: Default + Clone + Debug + Eq + Ord,
|
||||
R: RangeBounds<usize> + 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 extend_from_slice(&mut self, sli: &Box<[T]>);
|
||||
fn insert(&mut self, index: usize, item: T);
|
||||
fn is_empty(&self) -> bool;
|
||||
fn len(&self) -> usize;
|
||||
fn pop(&mut self) -> Option<T>;
|
||||
fn push(&mut self, item: T);
|
||||
fn remove(&mut self, index: usize) -> T;
|
||||
fn resize(&mut self, new_len: usize, new_val: T);
|
||||
fn swap_remove(&mut self, index: usize) -> T;
|
||||
fn truncate(&mut self, new_len: usize);
|
||||
}
|
||||
|
||||
equal_with(Vec::from_iter) {
|
||||
//fn split_off(&mut self, at: usize) -> impl IntoIterator<Item = T>;
|
||||
fn drain(&self, range: R) -> impl Iterator<Item = T>;
|
||||
fn iter(&self) -> impl Iterator<Item = &T>;
|
||||
fn iter_mut(&self) -> impl Iterator<Item = &mut T>;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
match self {
|
||||
// We are comparing ArrayVec with a limited capacity against
|
||||
// Vec to which you can push indefinitely. This is a behavior mismatch.
|
||||
// To compensate we skip adding any elements if it would exceed capacity.
|
||||
Self::insert { .. } | Self::push { .. } if model.len() == model.capacity() => {
|
||||
return;
|
||||
}
|
||||
Self::resize { new_len, .. } if new_len > model.capacity() => {
|
||||
return;
|
||||
}
|
||||
Self::extend_from_slice { sli } if model.len().saturating_add(sli.len()) > model.capacity() => {
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_array(mut x: u32) -> [u32; 32] {
|
||||
let mut tested = [0u32; 32];
|
||||
|
||||
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 mut array = rand_array(seed(data));
|
||||
let mut model = array.to_vec();
|
||||
let mut tested = SliceVec::from(&mut array);
|
||||
|
||||
while let Ok(op) =
|
||||
<op::Op<u32, ArbRange<usize>> as Arbitrary>::arbitrary(&mut ring)
|
||||
{
|
||||
#[cfg(fuzzing_debug)]
|
||||
eprintln!("{:?}", op);
|
||||
op.execute_and_compare(&mut model, &mut tested);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), ()> {
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -754,11 +754,11 @@ impl<A: Array> ArrayVec<A> {
|
||||
use core::ops::Bound;
|
||||
let start = match range.start_bound() {
|
||||
Bound::Included(x) => *x,
|
||||
Bound::Excluded(x) => x + 1,
|
||||
Bound::Excluded(x) => x.saturating_add(1),
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
let end = match range.end_bound() {
|
||||
Bound::Included(x) => x + 1,
|
||||
Bound::Included(x) => x.saturating_add(1),
|
||||
Bound::Excluded(x) => *x,
|
||||
Bound::Unbounded => self.len(),
|
||||
};
|
||||
|
||||
@@ -21,11 +21,11 @@ impl<'a, T: 'a + Default> ArrayVecDrain<'a, T> {
|
||||
let start = match range.start_bound() {
|
||||
Bound::Unbounded => 0,
|
||||
Bound::Included(&n) => n,
|
||||
Bound::Excluded(&n) => n + 1,
|
||||
Bound::Excluded(&n) => n.saturating_add(1),
|
||||
};
|
||||
let end = match range.end_bound() {
|
||||
Bound::Unbounded => arr.len(),
|
||||
Bound::Included(&n) => n + 1,
|
||||
Bound::Included(&n) => n.saturating_add(1),
|
||||
Bound::Excluded(&n) => n,
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -161,11 +161,11 @@ impl<'s, T> SliceVec<'s, T> {
|
||||
use core::ops::Bound;
|
||||
let start = match range.start_bound() {
|
||||
Bound::Included(x) => *x,
|
||||
Bound::Excluded(x) => x + 1,
|
||||
Bound::Excluded(x) => x.saturating_add(1),
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
let end = match range.end_bound() {
|
||||
Bound::Included(x) => x + 1,
|
||||
Bound::Included(x) => x.saturating_add(1),
|
||||
Bound::Excluded(x) => *x,
|
||||
Bound::Unbounded => self.len,
|
||||
};
|
||||
|
||||
+2
-2
@@ -789,11 +789,11 @@ impl<A: Array> TinyVec<A> {
|
||||
use core::ops::Bound;
|
||||
let start = match range.start_bound() {
|
||||
Bound::Included(x) => *x,
|
||||
Bound::Excluded(x) => x + 1,
|
||||
Bound::Excluded(x) => x.saturating_add(1),
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
let end = match range.end_bound() {
|
||||
Bound::Included(x) => x + 1,
|
||||
Bound::Included(x) => x.saturating_add(1),
|
||||
Bound::Excluded(x) => *x,
|
||||
Bound::Unbounded => self.len(),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user