Skip to content

Commit

Permalink
add to CI
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsn committed May 21, 2024
1 parent bd73c69 commit 82c7533
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 21 deletions.
1 change: 1 addition & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ jobs:
set -e
(cd profiling && cargo bolero test collections::string_table::tests::fuzz_string_table -T 1min)
(cd profiling && cargo bolero test collections::string_table::tests::fuzz_arena_allocator -T 1min)
(cd alloc && cargo bolero test chain::tests::fuzz -T 1min)
69 changes: 48 additions & 21 deletions alloc/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,7 @@ unsafe impl<A: Allocator + Clone> Allocator for ChainAllocator<A> {

debug_assert!(chain_node.remaining_capacity() >= layout.size());

let result = chain_node.linear.allocate(layout);
// If this fails, there's a bug in the allocator.
debug_assert!(result.is_ok());
result
chain_node.linear.allocate(layout)
}

unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
Expand Down Expand Up @@ -290,29 +287,59 @@ mod tests {
use super::*;
use allocator_api2::alloc::Global;

/// https://doc.rust-lang.org/beta/std/primitive.pointer.html#method.is_aligned_to
/// Convenience function until the std lib standardizes this.
fn is_aligned_to<T: ?Sized>(p: *const T, align: usize) -> bool {
(p as *const u8 as usize) % align == 0
}

#[test]
fn fuzz() {
bolero::check!()
.with_type::<(usize, usize, u32)>()
.for_each(|(size_hint, size, align_bits)| {
.with_type::<(usize, Vec<(usize, u32, usize, u8)>)>()
.for_each(|(size_hint, size_align_vec)| {
const MAX_SIZE: usize = 0x10000000;
// avoid SUMMARY: libFuzzer: out-of-memory
if *size_hint > MAX_SIZE {
return;
}
let allocator = ChainAllocator::new_in(*size_hint, Global);
if *size == 0 {return};
assert!(false);

// for now, only test 2**8 alignments
if *align_bits > 8 {return};
let Some(align) = 2usize.checked_pow(*align_bits) else {
return;
};
assert!(false);
for (size, align_bits, idx, val) in size_align_vec {
if *size == 0 || *size > MAX_SIZE {
return;
};
if idx >= size {
return;
}

let Ok(layout) = Layout::from_size_align(*size, align) else {
return;
};
let ptr = allocator.allocate(layout).unwrap();
// deallocate doesn't return memory to the allocator, but it shouldn't
// panic, as that prevents its use in containers like Vec.
unsafe { allocator.deallocate(ptr.cast(), layout) };
// Exit early if the alignment alone would be too big
if *align_bits > 32 {
return;
};

let align = 1usize << *align_bits;
let layout = Layout::from_size_align(*size, align).unwrap();

if layout.pad_to_align().size() > MAX_SIZE {
return;
};

if let Ok(mut ptr) = allocator.allocate(layout) {
assert!(is_aligned_to(ptr.as_ptr(), align));
let obj = unsafe { ptr.as_mut() };
// The object is guaranteed to be at least size, but can be larger
assert!(obj.len() >= *size);

// Test that writing and reading a random index in the object works.
obj[*idx] = *val;
assert_eq!(obj[*idx], *val);

// deallocate doesn't return memory to the allocator, but it shouldn't
// panic, as that prevents its use in containers like Vec.
unsafe { allocator.deallocate(ptr.cast(), layout) };
}
}
})
}

Expand Down

0 comments on commit 82c7533

Please sign in to comment.