| use fuzztest::domains::arbitrary::Arbitrary; |
| use fuzztest::domains::range::InRange; |
| use fuzztest::domains::Domain; |
| use fuzztest::fuzztest; |
| use rand::RngExt; |
| use std::mem::MaybeUninit; |
| |
| struct ByteVectorDomain {} |
| |
| impl ByteVectorDomain { |
| pub fn new() -> Self { |
| Self {} |
| } |
| } |
| |
| // Test-only domain. |
| impl Domain for ByteVectorDomain { |
| type UserValue<'user> = Vec<u8>; |
| type CorpusValue = Vec<u8>; |
| |
| fn init(&self, rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue> { |
| let mut val = vec![0u8; rng.random_range(0..100)]; |
| rng.fill(&mut val[..]); |
| Ok(val) |
| } |
| |
| fn mutate( |
| &self, |
| val: &mut Self::CorpusValue, |
| rng: &mut dyn rand::Rng, |
| only_shrink: bool, |
| ) -> anyhow::Result<()> { |
| if only_shrink { |
| if rng.random::<f32>() < 0.05 && !val.is_empty() { |
| val.remove(rng.random_range(..val.len())); |
| } |
| |
| for elem in val { |
| if *elem != 0 { |
| *elem -= 1; |
| } |
| } |
| |
| return Ok(()); |
| } |
| if rng.random::<f32>() < 0.05 { |
| val.insert(rng.random_range(0..=val.len()), rng.random()); |
| } |
| |
| if rng.random::<f32>() < 0.05 && !val.is_empty() { |
| val.remove(rng.random_range(..val.len())); |
| } |
| |
| let start = rng.random_range(0..=val.len()); |
| let end = rng.random_range(start..=val.len()); |
| rng.fill(&mut val[start..end]); |
| |
| Ok(()) |
| } |
| |
| fn get_user_value<'a>( |
| &self, |
| val: &'a Self::CorpusValue, |
| ) -> anyhow::Result<Self::UserValue<'a>> { |
| Ok(val.clone()) |
| } |
| } |
| |
| #[fuzztest(_a = Arbitrary::<bool>::default())] |
| fn bool_fuzz_test(_a: bool) {} |
| |
| #[fuzztest(_a = Arbitrary::<i32>::default())] |
| fn i32_fuzz_test(_a: i32) {} |
| |
| #[fuzztest( |
| _a = Arbitrary::<i32>::default(), |
| _b = Arbitrary::<f32>::default(), |
| _c = Arbitrary::<bool>::default(), |
| _d = ByteVectorDomain::new() |
| )] |
| fn multi_arg_fuzz_test(_a: i32, _b: f32, _c: bool, _d: Vec<u8>) {} |
| |
| // Designed to fail in a "rare" instance. |
| #[fuzztest(a = ByteVectorDomain::new())] |
| fn find_bug_fuzz_test(a: Vec<u8>) { |
| if !a.is_empty() && a[0] == 1 { |
| panic!("Bug found!"); |
| } |
| } |
| |
| // Designed to fail in an even rarer instance to prove that coverage is working. |
| #[fuzztest(a = ByteVectorDomain::new())] |
| fn find_rarer_bug_fuzz_test(a: Vec<u8>) { |
| if a.len() == 5 && a[0] == b'P' && a[1] == b'a' && a[2] == b'N' && a[3] == b'i' && a[4] == b'C' |
| { |
| panic!("Bug found!"); |
| } |
| } |
| |
| #[fuzztest(a = ByteVectorDomain::new(), b = ByteVectorDomain::new())] |
| fn find_rarer_bug_2_args_fuzz_test(a: Vec<u8>, b: Vec<u8>) { |
| if !a.is_empty() && a[0] >= 128 && !b.is_empty() && b[0] == 42 { |
| panic!("Bug found!"); |
| } |
| } |
| |
| #[fuzztest(a = ByteVectorDomain::new(), b = Arbitrary::<f32>::default(), c = InRange::<i32>::new(0, 100))] |
| fn find_rarer_bug_3_args_fuzz_test(a: Vec<u8>, b: f32, c: i32) { |
| if !a.is_empty() && a[0] >= 128 && b < 0.0 && c >= 95 { |
| panic!("Bug found!"); |
| } |
| } |
| #[fuzztest(a = ByteVectorDomain::new())] |
| fn use_after_free_asan_death_test(mut a: Vec<u8>) { |
| if !a.is_empty() && a[0] == 123 { |
| let ptr = a.as_mut_ptr(); |
| drop(a); |
| // Intentionally trigger a use-after-free bug for ASAN to detect. |
| unsafe { |
| *(std::hint::black_box(ptr)) = 1; |
| } |
| } |
| } |
| |
| #[fuzztest(a = ByteVectorDomain::new())] |
| fn msan_death_test(a: Vec<u8>) { |
| if !a.is_empty() && a[0] == 123 { |
| // Intentionally trigger an uninitialized memory bug for MSAN to detect. |
| unsafe { |
| let x: MaybeUninit<i32> = MaybeUninit::uninit(); |
| let y = std::hint::black_box(x).assume_init(); |
| println!("y: {}", y); |
| } |
| } |
| } |
| |
| struct FallibleDomain {} |
| |
| impl FallibleDomain { |
| pub fn new() -> Self { |
| Self {} |
| } |
| } |
| |
| impl Domain for FallibleDomain { |
| type UserValue<'user> = u32; |
| type CorpusValue = u32; |
| |
| fn init(&self, _rng: &mut dyn rand::Rng) -> anyhow::Result<Self::CorpusValue> { |
| Ok(0) |
| } |
| |
| fn mutate( |
| &self, |
| _val: &mut Self::CorpusValue, |
| _rng: &mut dyn rand::Rng, |
| _only_shrink: bool, |
| ) -> anyhow::Result<()> { |
| anyhow::bail!("Intentional mutate failure") |
| } |
| |
| fn get_user_value<'a>( |
| &self, |
| val: &'a Self::CorpusValue, |
| ) -> anyhow::Result<Self::UserValue<'a>> { |
| Ok(*val) |
| } |
| } |
| |
| #[fuzztest(a = FallibleDomain::new())] |
| fn fallible_fuzz_test(_a: u32) {} |