diff --git a/crates/fuzzing-support/Cargo.lock b/crates/fuzzing-support/Cargo.lock index 71891e7..4b5d20f 100644 --- a/crates/fuzzing-support/Cargo.lock +++ b/crates/fuzzing-support/Cargo.lock @@ -43,6 +43,7 @@ dependencies = [ "arbitrary", "bump-scope", "rangemap", + "zerocopy", ] [[package]] @@ -91,3 +92,23 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "zerocopy" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3da5f7220f919a6c7af7c856435a68ee1582fd7a77aa72936257d8335bd6f6" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5f54f3cc93cd80745404626681b4b9fca9a867bad5a8424b618eb0db1ae6ea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/crates/fuzzing-support/Cargo.toml b/crates/fuzzing-support/Cargo.toml index 75fd5e1..368274f 100644 --- a/crates/fuzzing-support/Cargo.toml +++ b/crates/fuzzing-support/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" bump-scope = { path = "../.." } arbitrary = { version = "1.3.2", features = ["derive"] } rangemap = "1.5.1" +zerocopy = { version = "0.8.7", features = ["derive"] } diff --git a/crates/fuzzing-support/src/lib.rs b/crates/fuzzing-support/src/lib.rs index 5a1c157..c120d10 100644 --- a/crates/fuzzing-support/src/lib.rs +++ b/crates/fuzzing-support/src/lib.rs @@ -13,6 +13,7 @@ pub mod bump_greedy_up; pub mod bump_up; pub mod bumping; mod from_bump_scope; +pub mod many_vecs; #[derive(Debug, Clone)] struct RcAllocator { diff --git a/crates/fuzzing-support/src/many_vecs.rs b/crates/fuzzing-support/src/many_vecs.rs new file mode 100644 index 0000000..8a15bf6 --- /dev/null +++ b/crates/fuzzing-support/src/many_vecs.rs @@ -0,0 +1,197 @@ +use arbitrary::Arbitrary; +use bump_scope::{allocator_api2::alloc::Global, Bump, BumpVec, MinimumAlignment, SupportedMinimumAlignment}; +use zerocopy::{FromBytes, Immutable, IntoBytes}; + +impl Fuzz { + pub fn run(self) { + if self.up { + self.run_dir::(); + } else { + self.run_dir::(); + } + } + + fn run_dir(self) { + match self.min_align { + MinAlign::A1 => self.run_dir_align::(), + MinAlign::A2 => self.run_dir_align::(), + MinAlign::A3 => self.run_dir_align::(), + MinAlign::A4 => self.run_dir_align::(), + MinAlign::A5 => self.run_dir_align::(), + } + } + + fn run_dir_align(self) + where + MinimumAlignment: SupportedMinimumAlignment, + { + let bump: Bump = Bump::new(); + + let mut vecs = self + .vecs + .iter() + .enumerate() + .map(|(i, kind)| { + let pattern = (i % 255) as u8; + match kind { + VecKind::T1 => VecObj::new::(&bump, pattern), + VecKind::T2 => VecObj::new::(&bump, pattern), + VecKind::T3 => VecObj::new::(&bump, pattern), + VecKind::T4 => VecObj::new::(&bump, pattern), + VecKind::T5 => VecObj::new::(&bump, pattern), + VecKind::T6 => VecObj::new::(&bump, pattern), + } + }) + .collect::>(); + + let vecs_len = vecs.len(); + + if vecs_len == 0 { + return; + } + + for operation in self.operations { + match operation { + Operation::Push(i) => { + let vec = &mut vecs[i % vecs_len]; + vec.push(); + vec.assert_valid(); + } + } + + for vec in &vecs { + vec.assert_valid(); + } + } + } +} + +#[derive(Debug, Arbitrary)] +pub struct Fuzz { + up: bool, + min_align: MinAlign, + + vecs: Vec, + operations: Vec, +} + +#[derive(Debug, Clone, Copy, Arbitrary)] +enum VecKind { + T1, + T2, + T3, + T4, + T5, + T6, +} + +#[derive(Debug, Arbitrary)] + +enum Operation { + Push(usize), +} + +trait VecTrait { + fn push(&mut self, bit_pattern: u8); + + fn assert_valid(&self, bit_pattern: u8); +} + +struct VecObj<'a> { + vec: Box, + bit_pattern: u8, +} + +impl<'a> VecObj<'a> { + fn new(bump: &'a Bump, bit_pattern: u8) -> Self + where + MinimumAlignment: SupportedMinimumAlignment, + T: Default + FromBytes + IntoBytes + Immutable + 'static, + { + Self { + vec: Box::new(BumpVec::::new_in(bump)), + bit_pattern, + } + } + + fn push(&mut self) { + let Self { vec, bit_pattern } = self; + vec.push(*bit_pattern); + } + + fn assert_valid(&self) { + let Self { vec, bit_pattern } = self; + vec.assert_valid(*bit_pattern); + } +} + +impl VecTrait for BumpVec<'_, '_, T, Global, MIN_ALIGN, UP> +where + MinimumAlignment: SupportedMinimumAlignment, + T: Default + FromBytes + IntoBytes + Immutable, +{ + fn push(&mut self, bit_pattern: u8) { + self.push(from_bit_pattern(bit_pattern)); + } + + fn assert_valid(&self, bit_pattern: u8) { + for &byte in self.as_slice().as_bytes() { + assert_eq!(byte, bit_pattern); + } + } +} + +fn from_bit_pattern(byte: u8) -> T { + let mut value = T::new_zeroed(); + value.as_mut_bytes().fill(byte); + value +} + +#[derive(Debug, Clone, Copy, Arbitrary)] +enum Align { + T1 = 1 << 0, + T2 = 1 << 1, + T3 = 1 << 2, + T4 = 1 << 3, + T5 = 1 << 4, + T6 = 1 << 5, +} + +#[derive(Debug, Clone, Copy, Arbitrary)] +enum MinAlign { + A1 = 1, + A2 = 2, + A3 = 4, + A4 = 8, + A5 = 16, +} + +#[repr(transparent)] +#[derive(Clone, Default, IntoBytes, FromBytes, Immutable)] +#[allow(dead_code)] +struct T1(u8); + +#[repr(transparent)] +#[derive(Clone, Default, IntoBytes, FromBytes, Immutable)] +#[allow(dead_code)] +struct T2(u16); + +#[repr(transparent)] +#[derive(Clone, Default, IntoBytes, FromBytes, Immutable)] +#[allow(dead_code)] +struct T3(u32); + +#[repr(transparent)] +#[derive(Clone, Default, IntoBytes, FromBytes, Immutable)] +#[allow(dead_code)] +struct T4(u64); + +#[repr(transparent)] +#[derive(Clone, Default, IntoBytes, FromBytes, Immutable)] +#[allow(dead_code)] +struct T5([u64; 2]); + +#[repr(transparent)] +#[derive(Clone, Default, IntoBytes, FromBytes, Immutable)] +#[allow(dead_code)] +struct T6([u64; 3]); diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index f9aa376..d0974f9 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -61,6 +61,7 @@ dependencies = [ "arbitrary", "bump-scope", "rangemap", + "zerocopy", ] [[package]] @@ -141,3 +142,23 @@ name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "zerocopy" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3da5f7220f919a6c7af7c856435a68ee1582fd7a77aa72936257d8335bd6f6" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5f54f3cc93cd80745404626681b4b9fca9a867bad5a8424b618eb0db1ae6ea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 8d18546..de093b9 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -52,3 +52,10 @@ path = "fuzz_targets/bump_greedy_down.rs" test = false doc = false bench = false + +[[bin]] +name = "many_vecs" +path = "fuzz_targets/many_vecs.rs" +test = false +doc = false +bench = false diff --git a/fuzz/fuzz_targets/many_vecs.rs b/fuzz/fuzz_targets/many_vecs.rs new file mode 100644 index 0000000..3fbdf84 --- /dev/null +++ b/fuzz/fuzz_targets/many_vecs.rs @@ -0,0 +1,6 @@ +#![no_main] + +use fuzzing_support::many_vecs::Fuzz; +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|fuzz: Fuzz| fuzz.run());