Skip to content

Commit

Permalink
test: refactor fuzz targets to mook more like many_vecs
Browse files Browse the repository at this point in the history
  • Loading branch information
bluurryy committed Oct 25, 2024
1 parent ee28ba5 commit 8e134cb
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 213 deletions.
340 changes: 168 additions & 172 deletions crates/fuzzing-support/src/allocator_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,193 +8,203 @@ use core::fmt::Debug;
use rangemap::RangeSet;
use std::{alloc::Layout, ops::Range, ptr::NonNull, rc::Rc};

fn do_fuzz(fuzz: Fuzz) {
if fuzz.up {
do_fuzz_dir::<true>(&fuzz);
} else {
do_fuzz_dir::<false>(&fuzz);
}
#[derive(Debug, Arbitrary)]
pub struct Fuzz {
up: bool,
min_align: MinAlign,

operations: Vec<Operation>,
}

fn do_fuzz_dir<const UP: bool>(fuzz: &Fuzz) {
match fuzz.min_align {
MinAlign::Shl0 => do_fuzz_dir_align::<UP, 1>(fuzz),
MinAlign::Shl1 => do_fuzz_dir_align::<UP, 2>(fuzz),
MinAlign::Shl2 => do_fuzz_dir_align::<UP, 4>(fuzz),
MinAlign::Shl3 => do_fuzz_dir_align::<UP, 8>(fuzz),
MinAlign::Shl4 => do_fuzz_dir_align::<UP, 16>(fuzz),
impl Fuzz {
pub fn run(self) {
if self.up {
self.run_dir::<true>();
} else {
self.run_dir::<false>();
}
}
}

fn do_fuzz_dir_align<const UP: bool, const MIN_ALIGN: usize>(fuzz: &Fuzz)
where
MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
{
dbg!(UP);
dbg!(MIN_ALIGN);

// We use rc to also check that allocator cloning works.
let allocator = RcAllocator::new(Rc::new(MaybeFailingAllocator::new(Global)));
let bump: Bump<_, MIN_ALIGN, UP> = Bump::with_capacity_in(Layout::new::<[u8; 32]>(), allocator);

let mut allocations = vec![];
let mut used_ranges = UsedRanges::default();

#[allow(clippy::unused_enumerate_index)]
for (_operation_i, &operation) in fuzz.operations.iter().enumerate() {
eprintln!("======================================");
eprintln!("OPERATION {_operation_i}");
dbg!(&allocations);
dbg!(&used_ranges);
dbg!(&bump);

match operation {
Operation::Allocate { layout, zero, fails } => unsafe {
let layout = layout.0;

bump.allocator().fails.set(fails);

let ptr = if zero {
bump.allocate_zeroed(layout)
} else {
bump.allocate(layout)
};

eprintln!("ALLOCATE");
dbg!(layout);
dbg!(&ptr);
fn run_dir<const UP: bool>(self) {
match self.min_align {
MinAlign::Shl0 => self.run_dir_align::<UP, 1>(),
MinAlign::Shl1 => self.run_dir_align::<UP, 2>(),
MinAlign::Shl2 => self.run_dir_align::<UP, 4>(),
MinAlign::Shl3 => self.run_dir_align::<UP, 8>(),
MinAlign::Shl4 => self.run_dir_align::<UP, 16>(),
}
}

if let Ok(ptr) = ptr {
assert_eq!(ptr.len(), layout.size());
assert!(ptr.is_aligned_to(layout.align()));
used_ranges.insert(ptr);
fn run_dir_align<const UP: bool, const MIN_ALIGN: usize>(self)
where
MinimumAlignment<MIN_ALIGN>: SupportedMinimumAlignment,
{
dbg!(UP);
dbg!(MIN_ALIGN);

if zero {
assert_zeroed(ptr);
}
// We use rc to also check that allocator cloning works.
let allocator = RcAllocator::new(Rc::new(MaybeFailingAllocator::new(Global)));
let bump: Bump<_, MIN_ALIGN, UP> = Bump::with_capacity_in(Layout::new::<[u8; 32]>(), allocator);

initialize(ptr);
assert_initialized(ptr);
let mut allocations = vec![];
let mut used_ranges = UsedRanges::default();

allocations.push(Allocation { ptr, layout });
}
},
Operation::Deallocate { index } => unsafe {
if allocations.is_empty() {
continue;
}
#[allow(clippy::unused_enumerate_index)]
for (_operation_i, &operation) in self.operations.iter().enumerate() {
eprintln!("======================================");
eprintln!("OPERATION {_operation_i}");
dbg!(&allocations);
dbg!(&used_ranges);
dbg!(&bump);

let i = index % allocations.len();
let Allocation { ptr, layout } = allocations.swap_remove(i);
match operation {
Operation::Allocate { layout, zero, fails } => unsafe {
let layout = layout.0;

eprintln!("DEALLOCATE");
dbg!(layout);
dbg!(&ptr);
bump.allocator().fails.set(fails);

assert_eq!(ptr.len(), layout.size());
assert!(ptr.is_aligned_to(layout.align()));
used_ranges.remove(ptr);
let ptr = if zero {
bump.allocate_zeroed(layout)
} else {
bump.allocate(layout)
};

assert_initialized(ptr);
deinitialize(ptr);
eprintln!("ALLOCATE");
dbg!(layout);
dbg!(&ptr);

bump.deallocate(ptr.cast(), layout);
},
Operation::Reallocate {
index,
layout: new_layout,
zero,
fails,
} => unsafe {
let mut new_layout = new_layout.0;

eprintln!("REALLOCATE");
dbg!(new_layout);
dbg!(index);

if allocations.is_empty() {
eprintln!("CANCELLED: NO ALLOCATIONS");
continue;
}

bump.allocator().fails.set(fails);

let i = index % allocations.len();
dbg!(i);

let Allocation {
ptr: old_ptr,
layout: old_layout,
} = allocations[i];

dbg!(old_layout);
dbg!(old_ptr);

assert_eq!(old_ptr.len(), old_layout.size());
assert!(old_ptr.is_aligned_to(old_layout.align()));
assert_initialized(old_ptr);

let new_ptr = if new_layout.size() > old_layout.size() {
if zero {
bump.grow_zeroed(old_ptr.cast(), old_layout, new_layout)
} else {
bump.grow(old_ptr.cast(), old_layout, new_layout)
if let Ok(ptr) = ptr {
assert_eq!(ptr.len(), layout.size());
assert!(ptr.is_aligned_to(layout.align()));
used_ranges.insert(ptr);

if zero {
assert_zeroed(ptr);
}

initialize(ptr);
assert_initialized(ptr);

allocations.push(Allocation { ptr, layout });
}
},
Operation::Deallocate { index } => unsafe {
if allocations.is_empty() {
continue;
}
} else {
bump.shrink(old_ptr.cast(), old_layout, new_layout)
};

dbg!(&new_ptr);
let i = index % allocations.len();
let Allocation { ptr, layout } = allocations.swap_remove(i);

if let Ok(new_ptr) = new_ptr {
#[allow(ambiguous_wide_pointer_comparisons)]
if new_ptr == old_ptr {
assert_eq!(new_ptr.len(), old_layout.size());
new_layout = Layout::from_size_align(old_layout.size(), new_layout.align()).unwrap();
} else {
assert_eq!(new_ptr.len(), new_layout.size());
eprintln!("DEALLOCATE");
dbg!(layout);
dbg!(&ptr);

assert_eq!(ptr.len(), layout.size());
assert!(ptr.is_aligned_to(layout.align()));
used_ranges.remove(ptr);

assert_initialized(ptr);
deinitialize(ptr);

bump.deallocate(ptr.cast(), layout);
},
Operation::Reallocate {
index,
layout: new_layout,
zero,
fails,
} => unsafe {
let mut new_layout = new_layout.0;

eprintln!("REALLOCATE");
dbg!(new_layout);
dbg!(index);

if allocations.is_empty() {
eprintln!("CANCELLED: NO ALLOCATIONS");
continue;
}

assert!(new_ptr.is_aligned_to(new_layout.align()));
bump.allocator().fails.set(fails);

let i = index % allocations.len();
dbg!(i);

let Allocation {
ptr: old_ptr,
layout: old_layout,
} = allocations[i];

if new_layout.size() > old_layout.size() {
let [old_part, new_part] = split_slice(new_ptr, old_layout.size());
assert_initialized(old_part);
dbg!(old_layout);
dbg!(old_ptr);

assert_eq!(old_ptr.len(), old_layout.size());
assert!(old_ptr.is_aligned_to(old_layout.align()));
assert_initialized(old_ptr);

let new_ptr = if new_layout.size() > old_layout.size() {
if zero {
assert_zeroed(new_part);
bump.grow_zeroed(old_ptr.cast(), old_layout, new_layout)
} else {
bump.grow(old_ptr.cast(), old_layout, new_layout)
}
} else {
bump.shrink(old_ptr.cast(), old_layout, new_layout)
};

dbg!(&new_ptr);

if let Ok(new_ptr) = new_ptr {
#[allow(ambiguous_wide_pointer_comparisons)]
if new_ptr == old_ptr {
assert_eq!(new_ptr.len(), old_layout.size());
new_layout = Layout::from_size_align(old_layout.size(), new_layout.align()).unwrap();
} else {
assert_eq!(new_ptr.len(), new_layout.size());
}

initialize(new_ptr);
}
assert!(new_ptr.is_aligned_to(new_layout.align()));

assert_initialized(new_ptr);
if new_layout.size() > old_layout.size() {
let [old_part, new_part] = split_slice(new_ptr, old_layout.size());
assert_initialized(old_part);

used_ranges.remove(old_ptr);
used_ranges.insert(new_ptr);
if zero {
assert_zeroed(new_part);
}

allocations[i] = Allocation {
ptr: new_ptr,
layout: new_layout,
initialize(new_ptr);
}

assert_initialized(new_ptr);

used_ranges.remove(old_ptr);
used_ranges.insert(new_ptr);

allocations[i] = Allocation {
ptr: new_ptr,
layout: new_layout,
}
}
}
},
},
}
}
}

eprintln!("====================================");
eprintln!("DONE WITH ALL OPERATIONS");
eprintln!("DROPPING REMAINING ALLOCATIONS");
eprintln!("====================================");

unsafe {
for Allocation { ptr, layout } in allocations {
dbg!(layout);
dbg!(ptr);
used_ranges.remove(ptr);
assert_initialized(ptr);
deinitialize(ptr);
bump.deallocate(ptr.cast(), layout);
eprintln!("====================================");
eprintln!("DONE WITH ALL OPERATIONS");
eprintln!("DROPPING REMAINING ALLOCATIONS");
eprintln!("====================================");

unsafe {
for Allocation { ptr, layout } in allocations {
dbg!(layout);
dbg!(ptr);
used_ranges.remove(ptr);
assert_initialized(ptr);
deinitialize(ptr);
bump.deallocate(ptr.cast(), layout);
}
}
}
}
Expand Down Expand Up @@ -306,20 +316,6 @@ struct Allocation {
layout: Layout,
}

#[derive(Debug, Arbitrary)]
pub struct Fuzz {
up: bool,
min_align: MinAlign,

operations: Vec<Operation>,
}

impl Fuzz {
pub fn run(self) {
do_fuzz(self)
}
}

#[derive(Debug, Clone, Copy, Arbitrary)]
enum MinAlign {
Shl0 = 1 << 0,
Expand Down
Loading

0 comments on commit 8e134cb

Please sign in to comment.