├── src ├── foreign │ ├── alloc │ │ ├── ffi │ │ │ ├── mod.rs │ │ │ └── c_str.rs │ │ ├── collections │ │ │ ├── mod.rs │ │ │ ├── vec_deque.rs │ │ │ ├── btree_set.rs │ │ │ ├── linked_list.rs │ │ │ ├── binary_heap.rs │ │ │ └── btree_map.rs │ │ ├── mod.rs │ │ ├── vec.rs │ │ ├── string.rs │ │ ├── borrow.rs │ │ ├── rc.rs │ │ ├── sync.rs │ │ └── boxed.rs │ ├── core │ │ ├── sync │ │ │ ├── mod.rs │ │ │ └── atomic.rs │ │ ├── unit.rs │ │ ├── mod.rs │ │ ├── iter.rs │ │ ├── bool.rs │ │ ├── slice.rs │ │ ├── cmp.rs │ │ ├── time.rs │ │ ├── marker.rs │ │ ├── option.rs │ │ ├── char.rs │ │ ├── result.rs │ │ ├── str.rs │ │ ├── tuple.rs │ │ ├── cell.rs │ │ ├── array.rs │ │ ├── ops.rs │ │ └── num.rs │ ├── std │ │ ├── ffi │ │ │ ├── mod.rs │ │ │ ├── c_str.rs │ │ │ └── os_str.rs │ │ ├── collections │ │ │ ├── mod.rs │ │ │ ├── hash_set.rs │ │ │ └── hash_map.rs │ │ ├── mod.rs │ │ ├── path.rs │ │ ├── sync.rs │ │ └── net.rs │ └── mod.rs ├── error.rs ├── size_hint.rs ├── tests.rs └── lib.rs ├── .gitignore ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzz_targets │ └── int_in_range.rs ├── publish.sh ├── derive ├── README.md ├── src │ ├── variant_attributes.rs │ ├── container_attributes.rs │ ├── field_attributes.rs │ └── lib.rs ├── Cargo.toml ├── LICENSE-MIT └── LICENSE-APACHE ├── tests ├── path.rs ├── bound.rs └── derive.rs ├── examples └── derive_enum.rs ├── LICENSE-MIT ├── Cargo.toml ├── .github └── workflows │ └── rust.yml ├── README.md ├── LICENSE-APACHE └── CHANGELOG.md /src/foreign/alloc/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | mod c_str; 2 | -------------------------------------------------------------------------------- /src/foreign/core/sync/mod.rs: -------------------------------------------------------------------------------- 1 | mod atomic; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | -------------------------------------------------------------------------------- /src/foreign/std/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | mod c_str; 2 | mod os_str; 3 | -------------------------------------------------------------------------------- /src/foreign/std/collections/mod.rs: -------------------------------------------------------------------------------- 1 | mod hash_map; 2 | mod hash_set; 3 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/mod.rs: -------------------------------------------------------------------------------- 1 | mod binary_heap; 2 | mod btree_map; 3 | mod btree_set; 4 | mod linked_list; 5 | mod vec_deque; 6 | -------------------------------------------------------------------------------- /src/foreign/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for foreign types. 2 | //! 3 | //! [`Arbitrary`]: crate::Arbitrary 4 | 5 | mod alloc; 6 | mod core; 7 | mod std; 8 | -------------------------------------------------------------------------------- /src/foreign/std/ffi/c_str.rs: -------------------------------------------------------------------------------- 1 | // impl Arbitrary for Box { 2 | // fn arbitrary(u: &mut Unstructured<'_>) -> Result { 3 | // ::arbitrary(u).map(|x| x.into_boxed_c_str()) 4 | // } 5 | // } 6 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | cd $(dirname $0)/derive 6 | 7 | cargo publish 8 | 9 | cd .. 10 | 11 | # Let the crates.io index figure out we've published `derive_arbitrary` already. 12 | sleep 5 13 | 14 | cargo publish 15 | -------------------------------------------------------------------------------- /src/foreign/std/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for [`std`] types, 2 | //! excluding those in [`core`] and [`alloc`]. 3 | //! 4 | //! [`Arbitrary`]: crate::Arbitrary 5 | 6 | mod collections; 7 | mod ffi; 8 | mod net; 9 | mod path; 10 | mod sync; 11 | -------------------------------------------------------------------------------- /src/foreign/alloc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for [`alloc`] types, 2 | //! excluding those in [`core`]. 3 | //! 4 | //! [`Arbitrary`]: crate::Arbitrary 5 | 6 | mod borrow; 7 | mod boxed; 8 | mod collections; 9 | mod ffi; 10 | mod rc; 11 | mod string; 12 | mod sync; 13 | mod vec; 14 | -------------------------------------------------------------------------------- /derive/README.md: -------------------------------------------------------------------------------- 1 | # `#[derive(Arbitrary)]` 2 | 3 | This crate implements support for automatically deriving [the `Arbitrary` 4 | trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html). 5 | 6 | Don't depend on this crate directly, though. Instead, enable the `"derive"` 7 | feature of the `arbitrary` crate. 8 | -------------------------------------------------------------------------------- /src/foreign/core/unit.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | impl<'a> Arbitrary<'a> for () { 4 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 5 | Ok(()) 6 | } 7 | 8 | #[inline] 9 | fn size_hint(_depth: usize) -> (usize, Option) { 10 | (0, Some(0)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/foreign/core/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementations of [`Arbitrary`] for [`core`] types. 2 | //! 3 | //! [`Arbitrary`]: crate::Arbitrary 4 | 5 | mod array; 6 | mod bool; 7 | mod cell; 8 | mod char; 9 | mod cmp; 10 | mod iter; 11 | mod marker; 12 | mod num; 13 | mod ops; 14 | mod option; 15 | mod result; 16 | mod slice; 17 | mod str; 18 | mod sync; 19 | mod time; 20 | mod tuple; 21 | mod unit; 22 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arbitrary-fuzz" 3 | version = "0.0.0" 4 | authors = ["Automatically generated"] 5 | publish = false 6 | edition = "2021" 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies] 12 | libfuzzer-sys = "0.4" 13 | 14 | [dependencies.arbitrary] 15 | path = ".." 16 | 17 | [[bin]] 18 | name = "int_in_range" 19 | path = "fuzz_targets/int_in_range.rs" 20 | test = false 21 | doc = false 22 | -------------------------------------------------------------------------------- /src/foreign/core/iter.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::iter::{empty, Empty}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Empty 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 11 | Ok(empty()) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(_depth: usize) -> (usize, Option) { 16 | (0, Some(0)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/foreign/std/path.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::{ffi::OsString, path::PathBuf}, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for PathBuf { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | ::arbitrary(u).map(From::from) 9 | } 10 | 11 | #[inline] 12 | fn size_hint(depth: usize) -> (usize, Option) { 13 | ::size_hint(depth) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/foreign/core/bool.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | /// Returns false, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 4 | impl<'a> Arbitrary<'a> for bool { 5 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 6 | Ok(>::arbitrary(u)? & 1 == 1) 7 | } 8 | 9 | #[inline] 10 | fn size_hint(depth: usize) -> (usize, Option) { 11 | >::size_hint(depth) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/foreign/core/slice.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | impl<'a> Arbitrary<'a> for &'a [u8] { 4 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 5 | let len = u.arbitrary_len::()?; 6 | u.bytes(len) 7 | } 8 | 9 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 10 | Ok(u.take_rest()) 11 | } 12 | 13 | #[inline] 14 | fn size_hint(_depth: usize) -> (usize, Option) { 15 | (0, None) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/foreign/alloc/vec.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::vec::Vec, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Vec 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/string.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::string::String, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for String { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | <&str as Arbitrary>::arbitrary(u).map(Into::into) 9 | } 10 | 11 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 12 | <&str as Arbitrary>::arbitrary_take_rest(u).map(Into::into) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | <&str as Arbitrary>::size_hint(depth) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/vec_deque.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::vec_deque::VecDeque, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for VecDeque 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/ffi/c_str.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::ffi::CString, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for CString { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | as Arbitrary>::arbitrary(u).map(|mut x| { 9 | x.retain(|&c| c != 0); 10 | // SAFETY: all zero bytes have been removed 11 | unsafe { Self::from_vec_unchecked(x) } 12 | }) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | as Arbitrary>::size_hint(depth) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/btree_set.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::btree_set::BTreeSet, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for BTreeSet 7 | where 8 | A: Arbitrary<'a> + Ord, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/linked_list.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::linked_list::LinkedList, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for LinkedList 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/binary_heap.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::binary_heap::BinaryHeap, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for BinaryHeap 7 | where 8 | A: Arbitrary<'a> + Ord, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | u.arbitrary_iter()?.collect() 12 | } 13 | 14 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 15 | u.arbitrary_take_rest_iter()?.collect() 16 | } 17 | 18 | #[inline] 19 | fn size_hint(_depth: usize) -> (usize, Option) { 20 | (0, None) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /derive/src/variant_attributes.rs: -------------------------------------------------------------------------------- 1 | use crate::ARBITRARY_ATTRIBUTE_NAME; 2 | use syn::*; 3 | 4 | pub fn not_skipped(variant: &&Variant) -> bool { 5 | !should_skip(variant) 6 | } 7 | 8 | fn should_skip(Variant { attrs, .. }: &Variant) -> bool { 9 | attrs 10 | .iter() 11 | .filter_map(|attr| { 12 | attr.path() 13 | .is_ident(ARBITRARY_ATTRIBUTE_NAME) 14 | .then(|| attr.parse_args::()) 15 | .and_then(Result::ok) 16 | }) 17 | .any(|meta| match meta { 18 | Meta::Path(path) => path.is_ident("skip"), 19 | _ => false, 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /src/foreign/alloc/collections/btree_map.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::collections::btree_map::BTreeMap, 4 | }; 5 | 6 | impl<'a, K, V> Arbitrary<'a> for BTreeMap 7 | where 8 | K: Arbitrary<'a> + Ord, 9 | V: Arbitrary<'a>, 10 | { 11 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 12 | u.arbitrary_iter()?.collect() 13 | } 14 | 15 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 16 | u.arbitrary_take_rest_iter()?.collect() 17 | } 18 | 19 | #[inline] 20 | fn size_hint(_depth: usize) -> (usize, Option) { 21 | (0, None) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/foreign/std/sync.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, MaxRecursionReached, Result, Unstructured}, 3 | std::sync::Mutex, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Mutex 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 21 | A::try_size_hint(depth) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/foreign/std/ffi/os_str.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::ffi::OsString, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for OsString { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | ::arbitrary(u).map(From::from) 9 | } 10 | 11 | #[inline] 12 | fn size_hint(depth: usize) -> (usize, Option) { 13 | ::size_hint(depth) 14 | } 15 | } 16 | 17 | // impl Arbitrary for Box { 18 | // fn arbitrary(u: &mut Unstructured<'_>) -> Result { 19 | // ::arbitrary(u).map(|x| x.into_boxed_osstr()) 20 | // 21 | // } 22 | // } 23 | -------------------------------------------------------------------------------- /src/foreign/core/cmp.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | core::cmp::Reverse, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Reverse 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/foreign/core/time.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | core::time::Duration, 4 | }; 5 | 6 | /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 7 | impl<'a> Arbitrary<'a> for Duration { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Ok(Self::new( 10 | ::arbitrary(u)?, 11 | u.int_in_range(0..=999_999_999)?, 12 | )) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | size_hint::and( 18 | ::size_hint(depth), 19 | ::size_hint(depth), 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/foreign/std/collections/hash_set.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::{ 4 | collections::hash_set::HashSet, 5 | hash::{BuildHasher, Hash}, 6 | }, 7 | }; 8 | 9 | impl<'a, A, S> Arbitrary<'a> for HashSet 10 | where 11 | A: Arbitrary<'a> + Eq + Hash, 12 | S: BuildHasher + Default, 13 | { 14 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 15 | u.arbitrary_iter()?.collect() 16 | } 17 | 18 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 19 | u.arbitrary_take_rest_iter()?.collect() 20 | } 21 | 22 | #[inline] 23 | fn size_hint(_depth: usize) -> (usize, Option) { 24 | (0, None) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/foreign/core/marker.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::marker::{PhantomData, PhantomPinned}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for PhantomData 7 | where 8 | A: ?Sized, 9 | { 10 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 11 | Ok(PhantomData) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(_depth: usize) -> (usize, Option) { 16 | (0, Some(0)) 17 | } 18 | } 19 | 20 | impl<'a> Arbitrary<'a> for PhantomPinned { 21 | fn arbitrary(_: &mut Unstructured<'a>) -> Result { 22 | Ok(PhantomPinned) 23 | } 24 | 25 | #[inline] 26 | fn size_hint(_depth: usize) -> (usize, Option) { 27 | (0, Some(0)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/foreign/std/collections/hash_map.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | std::{ 4 | collections::hash_map::HashMap, 5 | hash::{BuildHasher, Hash}, 6 | }, 7 | }; 8 | 9 | impl<'a, K, V, S> Arbitrary<'a> for HashMap 10 | where 11 | K: Arbitrary<'a> + Eq + Hash, 12 | V: Arbitrary<'a>, 13 | S: BuildHasher + Default, 14 | { 15 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 16 | u.arbitrary_iter()?.collect() 17 | } 18 | 19 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 20 | u.arbitrary_take_rest_iter()?.collect() 21 | } 22 | 23 | #[inline] 24 | fn size_hint(_depth: usize) -> (usize, Option) { 25 | (0, None) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/foreign/alloc/borrow.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::borrow::{Cow, ToOwned}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Cow<'a, A> 7 | where 8 | A: ToOwned + ?Sized + 'a, 9 | ::Owned: Arbitrary<'a>, 10 | { 11 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 12 | Arbitrary::arbitrary(u).map(Cow::Owned) 13 | } 14 | 15 | #[inline] 16 | fn size_hint(depth: usize) -> (usize, Option) { 17 | Self::try_size_hint(depth).unwrap_or_default() 18 | } 19 | 20 | #[inline] 21 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 22 | size_hint::try_recursion_guard(depth, |depth| { 23 | <::Owned as Arbitrary>::try_size_hint(depth) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/path.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "derive")] 2 | // Various structs/fields that we are deriving `Arbitrary` for aren't actually 3 | // used except to show off the derive. 4 | #![allow(dead_code)] 5 | 6 | // Regression test for ensuring the derives work without Arbitrary being imported 7 | 8 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 9 | pub struct Struct { 10 | x: u8, 11 | y: u8, 12 | } 13 | 14 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 15 | pub struct Tuple(u8); 16 | 17 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 18 | pub struct Unit(u8); 19 | 20 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 21 | pub enum Enum { 22 | X(u8), 23 | Y(u8), 24 | } 25 | 26 | #[derive(arbitrary::Arbitrary, Clone, Debug)] 27 | struct EndingInVec(u8, bool, u32, Vec); 28 | 29 | #[derive(arbitrary::Arbitrary, Debug)] 30 | struct Generic { 31 | inner: T, 32 | } 33 | -------------------------------------------------------------------------------- /derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "derive_arbitrary" 3 | version = "1.4.2" # Make sure it matches the version of the arbitrary crate itself (not including the patch version) 4 | authors = [ 5 | "The Rust-Fuzz Project Developers", 6 | "Nick Fitzgerald ", 7 | "Manish Goregaokar ", 8 | "Andre Bogus ", 9 | "Corey Farwell ", 10 | ] 11 | categories = ["development-tools::testing"] 12 | edition = "2021" 13 | keywords = ["arbitrary", "testing", "derive", "macro"] 14 | readme = "README.md" 15 | description = "Derives arbitrary traits" 16 | license = "MIT OR Apache-2.0" 17 | repository = "https://github.com/rust-fuzz/arbitrary" 18 | documentation = "https://docs.rs/arbitrary/" 19 | rust-version = "1.63.0" 20 | 21 | [dependencies] 22 | proc-macro2 = "1.0" 23 | quote = "1.0" 24 | syn = { version = "2", features = ['derive', 'parsing', 'extra-traits'] } 25 | 26 | [lib] 27 | proc-macro = true 28 | -------------------------------------------------------------------------------- /examples/derive_enum.rs: -------------------------------------------------------------------------------- 1 | //! A simple example of deriving the `Arbitrary` trait for an `enum`. 2 | //! 3 | //! Note that this requires enabling the "derive" cargo feature. 4 | 5 | // Various enums/fields that we are deriving `Arbitrary` for aren't actually 6 | // used except to show off the derive. 7 | #![allow(dead_code)] 8 | 9 | use arbitrary::{Arbitrary, Unstructured}; 10 | 11 | #[derive(Arbitrary, Debug)] 12 | enum MyEnum { 13 | Unit, 14 | Tuple(bool, u32), 15 | Struct { 16 | x: i8, 17 | y: (u8, i32), 18 | }, 19 | 20 | #[arbitrary(skip)] 21 | Skipped(usize), 22 | } 23 | 24 | fn main() { 25 | let raw = b"This is some raw, unstructured data!"; 26 | 27 | let mut unstructured = Unstructured::new(raw); 28 | 29 | let instance = MyEnum::arbitrary(&mut unstructured) 30 | .expect("`unstructured` has enough underlying data to create all variants of `MyEnum`"); 31 | 32 | println!("Here is an arbitrary enum: {:?}", instance); 33 | } 34 | -------------------------------------------------------------------------------- /src/foreign/core/option.rs: -------------------------------------------------------------------------------- 1 | use crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; 2 | 3 | /// Returns `None`, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 4 | impl<'a, A> Arbitrary<'a> for Option 5 | where 6 | A: Arbitrary<'a>, 7 | { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Ok(if >::arbitrary(u)? { 10 | Some(Arbitrary::arbitrary(u)?) 11 | } else { 12 | None 13 | }) 14 | } 15 | 16 | #[inline] 17 | fn size_hint(depth: usize) -> (usize, Option) { 18 | Self::try_size_hint(depth).unwrap_or_default() 19 | } 20 | 21 | #[inline] 22 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 23 | Ok(size_hint::and( 24 | ::try_size_hint(depth)?, 25 | size_hint::or((0, Some(0)), ::try_size_hint(depth)?), 26 | )) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/foreign/core/char.rs: -------------------------------------------------------------------------------- 1 | use crate::{Arbitrary, Result, Unstructured}; 2 | 3 | /// Returns '\0', not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 4 | impl<'a> Arbitrary<'a> for char { 5 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 6 | // The highest unicode code point is 0x11_FFFF 7 | const CHAR_END: u32 = 0x11_0000; 8 | // The size of the surrogate blocks 9 | const SURROGATES_START: u32 = 0xD800; 10 | let mut c = >::arbitrary(u)? % CHAR_END; 11 | if let Some(c) = char::from_u32(c) { 12 | Ok(c) 13 | } else { 14 | // We found a surrogate, wrap and try again 15 | c -= SURROGATES_START; 16 | Ok(char::from_u32(c) 17 | .expect("Generated character should be valid! This is a bug in arbitrary-rs")) 18 | } 19 | } 20 | 21 | #[inline] 22 | fn size_hint(depth: usize) -> (usize, Option) { 23 | >::size_hint(depth) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/foreign/core/result.rs: -------------------------------------------------------------------------------- 1 | use crate::{size_hint, Arbitrary, Error, MaxRecursionReached, Unstructured}; 2 | 3 | impl<'a, T, E> Arbitrary<'a> for Result 4 | where 5 | T: Arbitrary<'a>, 6 | E: Arbitrary<'a>, 7 | { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Ok(if >::arbitrary(u)? { 10 | Ok(::arbitrary(u)?) 11 | } else { 12 | Err(::arbitrary(u)?) 13 | }) 14 | } 15 | 16 | #[inline] 17 | fn size_hint(depth: usize) -> (usize, Option) { 18 | Self::try_size_hint(depth).unwrap_or_default() 19 | } 20 | 21 | #[inline] 22 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 23 | Ok(size_hint::and( 24 | ::size_hint(depth), 25 | size_hint::or( 26 | ::try_size_hint(depth)?, 27 | ::try_size_hint(depth)?, 28 | ), 29 | )) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Manish Goregaokar 4 | 5 | Permission is hereby granted, free of charge, to any 6 | person obtaining a copy of this software and associated 7 | documentation files (the "Software"), to deal in the 8 | Software without restriction, including without 9 | limitation the rights to use, copy, modify, merge, 10 | publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software 12 | is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions 17 | of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 20 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 21 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 22 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 23 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 26 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | DEALINGS IN THE SOFTWARE. 28 | -------------------------------------------------------------------------------- /derive/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Manish Goregaokar 4 | 5 | Permission is hereby granted, free of charge, to any 6 | person obtaining a copy of this software and associated 7 | documentation files (the "Software"), to deal in the 8 | Software without restriction, including without 9 | limitation the rights to use, copy, modify, merge, 10 | publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software 12 | is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions 17 | of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 20 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 21 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 22 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 23 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 26 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 | DEALINGS IN THE SOFTWARE. 28 | -------------------------------------------------------------------------------- /src/foreign/core/str.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::str, 4 | }; 5 | 6 | fn arbitrary_str<'a>(u: &mut Unstructured<'a>, size: usize) -> Result<&'a str> { 7 | match str::from_utf8(u.peek_bytes(size).unwrap()) { 8 | Ok(s) => { 9 | u.bytes(size).unwrap(); 10 | Ok(s) 11 | } 12 | Err(e) => { 13 | let i = e.valid_up_to(); 14 | let valid = u.bytes(i).unwrap(); 15 | let s = unsafe { 16 | debug_assert!(str::from_utf8(valid).is_ok()); 17 | str::from_utf8_unchecked(valid) 18 | }; 19 | Ok(s) 20 | } 21 | } 22 | } 23 | 24 | impl<'a> Arbitrary<'a> for &'a str { 25 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 26 | let size = u.arbitrary_len::()?; 27 | arbitrary_str(u, size) 28 | } 29 | 30 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 31 | let size = u.len(); 32 | arbitrary_str(&mut u, size) 33 | } 34 | 35 | #[inline] 36 | fn size_hint(_depth: usize) -> (usize, Option) { 37 | (0, None) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/foreign/core/sync/atomic.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, Result, Unstructured}, 3 | core::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize}, 4 | }; 5 | 6 | /// Returns false, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 7 | impl<'a> Arbitrary<'a> for AtomicBool { 8 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 9 | Arbitrary::arbitrary(u).map(Self::new) 10 | } 11 | 12 | #[inline] 13 | fn size_hint(depth: usize) -> (usize, Option) { 14 | >::size_hint(depth) 15 | } 16 | } 17 | 18 | /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 19 | impl<'a> Arbitrary<'a> for AtomicIsize { 20 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 21 | Arbitrary::arbitrary(u).map(Self::new) 22 | } 23 | 24 | #[inline] 25 | fn size_hint(depth: usize) -> (usize, Option) { 26 | >::size_hint(depth) 27 | } 28 | } 29 | 30 | /// Returns zero, not an error, if this `Unstructured` [is empty][Unstructured::is_empty]. 31 | impl<'a> Arbitrary<'a> for AtomicUsize { 32 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 33 | Arbitrary::arbitrary(u).map(Self::new) 34 | } 35 | 36 | #[inline] 37 | fn size_hint(depth: usize) -> (usize, Option) { 38 | >::size_hint(depth) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/int_in_range.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use arbitrary::{unstructured::Int, Arbitrary, Result, Unstructured}; 4 | use libfuzzer_sys::fuzz_target; 5 | use std::{fmt::Display, ops::RangeInclusive}; 6 | 7 | fuzz_target!(|data: &[u8]| { 8 | fuzz(data).expect("`int_in_range` should never return an error"); 9 | }); 10 | 11 | fn fuzz(data: &[u8]) -> Result<()> { 12 | let mut u = Unstructured::new(data); 13 | 14 | let choices = [ 15 | assert_in_range::, 16 | assert_in_range::, 17 | assert_in_range::, 18 | assert_in_range::, 19 | assert_in_range::, 20 | assert_in_range::, 21 | assert_in_range::, 22 | assert_in_range::, 23 | assert_in_range::, 24 | assert_in_range::, 25 | assert_in_range::, 26 | assert_in_range::, 27 | ]; 28 | 29 | let f = u.choose(&choices[..])?; 30 | f(&mut u) 31 | } 32 | 33 | fn assert_in_range<'a, 'b, T>(u: &'a mut Unstructured<'b>) -> Result<()> 34 | where 35 | T: Arbitrary<'b> + Int + Display, 36 | { 37 | let range = RangeInclusive::::arbitrary(u)?; 38 | let start = *range.start(); 39 | let end = *range.end(); 40 | 41 | let x = u.int_in_range(range)?; 42 | 43 | if start <= x && x <= end { 44 | return Ok(()); 45 | } 46 | 47 | let ty = std::any::type_name::(); 48 | panic!("{ty}: {x} is not within {start}..={end}",); 49 | } 50 | -------------------------------------------------------------------------------- /src/foreign/alloc/rc.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::rc::Rc, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Rc 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for Rc<[A]> 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | u.arbitrary_iter()?.collect() 31 | } 32 | 33 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 34 | u.arbitrary_take_rest_iter()?.collect() 35 | } 36 | 37 | #[inline] 38 | fn size_hint(_depth: usize) -> (usize, Option) { 39 | (0, None) 40 | } 41 | } 42 | 43 | impl<'a> Arbitrary<'a> for Rc { 44 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 45 | <&str as Arbitrary>::arbitrary(u).map(Into::into) 46 | } 47 | 48 | #[inline] 49 | fn size_hint(depth: usize) -> (usize, Option) { 50 | <&str as Arbitrary>::size_hint(depth) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/foreign/alloc/sync.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::sync::Arc, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Arc 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for Arc<[A]> 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | u.arbitrary_iter()?.collect() 31 | } 32 | 33 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 34 | u.arbitrary_take_rest_iter()?.collect() 35 | } 36 | 37 | #[inline] 38 | fn size_hint(_depth: usize) -> (usize, Option) { 39 | (0, None) 40 | } 41 | } 42 | 43 | impl<'a> Arbitrary<'a> for Arc { 44 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 45 | <&str as Arbitrary>::arbitrary(u).map(Into::into) 46 | } 47 | 48 | #[inline] 49 | fn size_hint(depth: usize) -> (usize, Option) { 50 | <&str as Arbitrary>::size_hint(depth) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/foreign/alloc/boxed.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::boxed::Box, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Box 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 21 | size_hint::try_recursion_guard(depth, ::try_size_hint) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for Box<[A]> 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | u.arbitrary_iter()?.collect() 31 | } 32 | 33 | fn arbitrary_take_rest(u: Unstructured<'a>) -> Result { 34 | u.arbitrary_take_rest_iter()?.collect() 35 | } 36 | 37 | #[inline] 38 | fn size_hint(_depth: usize) -> (usize, Option) { 39 | (0, None) 40 | } 41 | } 42 | 43 | impl<'a> Arbitrary<'a> for Box { 44 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 45 | ::arbitrary(u).map(|x| x.into_boxed_str()) 46 | } 47 | 48 | #[inline] 49 | fn size_hint(depth: usize) -> (usize, Option) { 50 | ::size_hint(depth) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/foreign/core/tuple.rs: -------------------------------------------------------------------------------- 1 | use crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; 2 | 3 | macro_rules! arbitrary_tuple { 4 | () => {}; 5 | ($last: ident $($xs: ident)*) => { 6 | arbitrary_tuple!($($xs)*); 7 | 8 | impl<'a, $($xs,)* $last> Arbitrary<'a> for ($($xs,)* $last,) 9 | where 10 | $($xs: Arbitrary<'a>,)* 11 | $last: Arbitrary<'a>, 12 | { 13 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 14 | Ok(($($xs::arbitrary(u)?,)* Arbitrary::arbitrary(u)?,)) 15 | } 16 | 17 | #[allow(unused_mut, non_snake_case)] 18 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 19 | $(let $xs = $xs::arbitrary(&mut u)?;)* 20 | let $last = $last::arbitrary_take_rest(u)?; 21 | Ok(($($xs,)* $last,)) 22 | } 23 | 24 | #[inline] 25 | fn size_hint(depth: usize) -> (usize, Option) { 26 | Self::try_size_hint(depth).unwrap_or_default() 27 | } 28 | #[inline] 29 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 30 | Ok(size_hint::and_all(&[ 31 | <$last as Arbitrary>::try_size_hint(depth)?, 32 | $( <$xs as Arbitrary>::try_size_hint(depth)?),* 33 | ])) 34 | } 35 | } 36 | }; 37 | } 38 | arbitrary_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z); 39 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arbitrary" 3 | version = "1.4.2" # Make sure this matches the derive crate version (not including the patch version) 4 | authors = [ 5 | "The Rust-Fuzz Project Developers", 6 | "Nick Fitzgerald ", 7 | "Manish Goregaokar ", 8 | "Simonas Kazlauskas ", 9 | "Brian L. Troutwine ", 10 | "Corey Farwell ", 11 | ] 12 | categories = ["development-tools::testing"] 13 | edition = "2021" 14 | keywords = ["arbitrary", "testing"] 15 | readme = "README.md" 16 | description = "The trait for generating structured data from unstructured data" 17 | license = "MIT OR Apache-2.0" 18 | repository = "https://github.com/rust-fuzz/arbitrary/" 19 | documentation = "https://docs.rs/arbitrary/" 20 | rust-version = "1.63.0" # Keep in sync with version documented in the README.md 21 | include = ["Cargo.toml", "CHANGELOG.md", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs", "tests/**/*.rs", "examples/**/*.rs"] 22 | 23 | [dependencies] 24 | derive_arbitrary = { version = "~1.4.0", path = "./derive", optional = true } 25 | 26 | [features] 27 | # Turn this feature on to enable support for `#[derive(Arbitrary)]`. 28 | derive = ["derive_arbitrary"] 29 | 30 | [[example]] 31 | name = "derive_enum" 32 | required-features = ["derive"] 33 | 34 | [[test]] 35 | name = "derive" 36 | path = "./tests/derive.rs" 37 | required-features = ["derive"] 38 | 39 | [workspace] 40 | members = ["./fuzz"] 41 | 42 | [dev-dependencies] 43 | exhaustigen = "0.1.0" 44 | -------------------------------------------------------------------------------- /src/foreign/core/cell.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, MaxRecursionReached, Result, Unstructured}, 3 | core::cell::{Cell, RefCell, UnsafeCell}, 4 | }; 5 | 6 | impl<'a, A> Arbitrary<'a> for Cell 7 | where 8 | A: Arbitrary<'a>, 9 | { 10 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 11 | Arbitrary::arbitrary(u).map(Self::new) 12 | } 13 | 14 | #[inline] 15 | fn size_hint(depth: usize) -> (usize, Option) { 16 | Self::try_size_hint(depth).unwrap_or_default() 17 | } 18 | 19 | #[inline] 20 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 21 | >::try_size_hint(depth) 22 | } 23 | } 24 | 25 | impl<'a, A> Arbitrary<'a> for RefCell 26 | where 27 | A: Arbitrary<'a>, 28 | { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | Arbitrary::arbitrary(u).map(Self::new) 31 | } 32 | 33 | #[inline] 34 | fn size_hint(depth: usize) -> (usize, Option) { 35 | Self::try_size_hint(depth).unwrap_or_default() 36 | } 37 | 38 | #[inline] 39 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 40 | >::try_size_hint(depth) 41 | } 42 | } 43 | 44 | impl<'a, A> Arbitrary<'a> for UnsafeCell 45 | where 46 | A: Arbitrary<'a>, 47 | { 48 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 49 | Arbitrary::arbitrary(u).map(Self::new) 50 | } 51 | 52 | #[inline] 53 | fn size_hint(depth: usize) -> (usize, Option) { 54 | Self::try_size_hint(depth).unwrap_or_default() 55 | } 56 | 57 | #[inline] 58 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 59 | >::try_size_hint(depth) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | vanilla_build: 7 | name: Vanilla Build 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - run: rustup update 12 | - name: Build 13 | run: cargo build --verbose --all 14 | - name: Run tests 15 | run: cargo test --verbose --all 16 | all_features_build: 17 | name: All Features Enabled Build 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | - run: rustup update 22 | - name: Build 23 | run: cargo build --verbose --all-features --all 24 | - name: Run tests 25 | run: cargo test --verbose --all-features --all 26 | - name: Build Examples 27 | run: cargo build --examples --all-features --all 28 | msrv: 29 | name: Minimum Supported Rust Version 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v3 33 | - run: rustup toolchain add 1.63 34 | - name: Build 35 | run: cargo +1.63 check --lib --all-features 36 | clippy: 37 | name: Clippy 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v3 41 | - run: rustup update 42 | - run: rustup component add clippy 43 | - run: cargo clippy --all-features --workspace -- -Dclippy::all 44 | rustfmt: 45 | name: Check rustfmt 46 | runs-on: ubuntu-latest 47 | steps: 48 | - uses: actions/checkout@v3 49 | - run: rustup update 50 | - run: rustup component add rustfmt --toolchain stable 51 | - run: cargo +stable fmt --all -- --check 52 | fuzz: 53 | name: Run `int_in_range` fuzz target 54 | runs-on: ubuntu-latest 55 | steps: 56 | - uses: actions/checkout@v3 57 | - run: rustup update 58 | - name: "Install nightly" 59 | run: rustup toolchain install nightly && rustup default nightly 60 | - name: "Install `cargo-fuzz`" 61 | run: cargo install cargo-fuzz 62 | - name: "Fuzz for 3 minutes" 63 | run: cargo fuzz run int_in_range -- -max_total_time=$((3 * 60)) 64 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{error, fmt}; 2 | 3 | /// An enumeration of buffer creation errors 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 5 | #[non_exhaustive] 6 | pub enum Error { 7 | /// No choices were provided to the Unstructured::choose call 8 | EmptyChoose, 9 | /// There was not enough underlying data to fulfill some request for raw 10 | /// bytes. 11 | /// 12 | /// Note that outside of [`Unstructured::bytes`][crate::Unstructured::bytes], 13 | /// most APIs do *not* return this error when running out of underlying arbitrary bytes 14 | /// but silently return some default value instead. 15 | NotEnoughData, 16 | /// The input bytes were not of the right format 17 | IncorrectFormat, 18 | } 19 | 20 | impl fmt::Display for Error { 21 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 22 | match self { 23 | Error::EmptyChoose => write!( 24 | f, 25 | "`arbitrary::Unstructured::choose` must be given a non-empty set of choices" 26 | ), 27 | Error::NotEnoughData => write!( 28 | f, 29 | "There is not enough underlying raw data to construct an `Arbitrary` instance" 30 | ), 31 | Error::IncorrectFormat => write!( 32 | f, 33 | "The raw data is not of the correct format to construct this type" 34 | ), 35 | } 36 | } 37 | } 38 | 39 | impl error::Error for Error {} 40 | 41 | /// A `Result` with the error type fixed as `arbitrary::Error`. 42 | /// 43 | /// Either an `Ok(T)` or `Err(arbitrary::Error)`. 44 | pub type Result = std::result::Result; 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | // Often people will import our custom `Result` type because 99.9% of 49 | // results in a file will be `arbitrary::Result` but then have that one last 50 | // 0.1% that want to have a custom error type. Don't make them prefix that 51 | // 0.1% as `std::result::Result`; instead, let `arbitrary::Result` have an 52 | // overridable error type. 53 | #[test] 54 | fn can_use_custom_error_types_with_result() -> super::Result<(), String> { 55 | Ok(()) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/foreign/core/array.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | core::{ 4 | array, 5 | mem::{self, MaybeUninit}, 6 | ptr, 7 | }, 8 | }; 9 | 10 | /// Helper to safely create arrays since the standard library doesn't 11 | /// provide one yet. Shouldn't be necessary in the future. 12 | struct ArrayGuard { 13 | dst: *mut T, 14 | initialized: usize, 15 | } 16 | 17 | impl Drop for ArrayGuard { 18 | fn drop(&mut self) { 19 | debug_assert!(self.initialized <= N); 20 | let initialized_part = ptr::slice_from_raw_parts_mut(self.dst, self.initialized); 21 | unsafe { 22 | ptr::drop_in_place(initialized_part); 23 | } 24 | } 25 | } 26 | 27 | fn try_create_array(mut cb: F) -> Result<[T; N]> 28 | where 29 | F: FnMut(usize) -> Result, 30 | { 31 | let mut array: MaybeUninit<[T; N]> = MaybeUninit::uninit(); 32 | let array_ptr = array.as_mut_ptr(); 33 | let dst = array_ptr as _; 34 | let mut guard: ArrayGuard = ArrayGuard { 35 | dst, 36 | initialized: 0, 37 | }; 38 | unsafe { 39 | for (idx, value_ptr) in (*array.as_mut_ptr()).iter_mut().enumerate() { 40 | ptr::write(value_ptr, cb(idx)?); 41 | guard.initialized += 1; 42 | } 43 | mem::forget(guard); 44 | Ok(array.assume_init()) 45 | } 46 | } 47 | 48 | impl<'a, T, const N: usize> Arbitrary<'a> for [T; N] 49 | where 50 | T: Arbitrary<'a>, 51 | { 52 | #[inline] 53 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 54 | try_create_array(|_| >::arbitrary(u)) 55 | } 56 | 57 | #[inline] 58 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 59 | let mut array = Self::arbitrary(&mut u)?; 60 | if let Some(last) = array.last_mut() { 61 | *last = Arbitrary::arbitrary_take_rest(u)?; 62 | } 63 | Ok(array) 64 | } 65 | 66 | #[inline] 67 | fn size_hint(depth: usize) -> (usize, Option) { 68 | Self::try_size_hint(depth).unwrap_or_default() 69 | } 70 | 71 | #[inline] 72 | fn try_size_hint(depth: usize) -> Result<(usize, Option), crate::MaxRecursionReached> { 73 | let hint = ::try_size_hint(depth)?; 74 | Ok(size_hint::and_all(&array::from_fn::<_, N, _>(|_| hint))) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /derive/src/container_attributes.rs: -------------------------------------------------------------------------------- 1 | use crate::ARBITRARY_ATTRIBUTE_NAME; 2 | use syn::{ 3 | parse::Error, punctuated::Punctuated, DeriveInput, Expr, ExprLit, Lit, Meta, MetaNameValue, 4 | Token, TypeParam, 5 | }; 6 | 7 | pub struct ContainerAttributes { 8 | /// Specify type bounds to be applied to the derived `Arbitrary` implementation instead of the 9 | /// default inferred bounds. 10 | /// 11 | /// ```ignore 12 | /// #[arbitrary(bound = "T: Default, U: Debug")] 13 | /// ``` 14 | /// 15 | /// Multiple attributes will be combined as long as they don't conflict, e.g. 16 | /// 17 | /// ```ignore 18 | /// #[arbitrary(bound = "T: Default")] 19 | /// #[arbitrary(bound = "U: Default")] 20 | /// ``` 21 | pub bounds: Option>>, 22 | } 23 | 24 | impl ContainerAttributes { 25 | pub fn from_derive_input(derive_input: &DeriveInput) -> Result { 26 | let mut bounds = None; 27 | 28 | for attr in &derive_input.attrs { 29 | if !attr.path().is_ident(ARBITRARY_ATTRIBUTE_NAME) { 30 | continue; 31 | } 32 | 33 | let meta_list = match attr.meta { 34 | Meta::List(ref l) => l, 35 | _ => { 36 | return Err(Error::new_spanned( 37 | attr, 38 | format!( 39 | "invalid `{}` attribute. expected list", 40 | ARBITRARY_ATTRIBUTE_NAME 41 | ), 42 | )) 43 | } 44 | }; 45 | 46 | for nested_meta in 47 | meta_list.parse_args_with(Punctuated::::parse_terminated)? 48 | { 49 | match nested_meta { 50 | Meta::NameValue(MetaNameValue { 51 | path, 52 | value: 53 | Expr::Lit(ExprLit { 54 | lit: Lit::Str(bound_str_lit), 55 | .. 56 | }), 57 | .. 58 | }) if path.is_ident("bound") => { 59 | bounds 60 | .get_or_insert_with(Vec::new) 61 | .push(bound_str_lit.parse_with(Punctuated::parse_terminated)?); 62 | } 63 | _ => { 64 | return Err(Error::new_spanned( 65 | attr, 66 | format!( 67 | "invalid `{}` attribute. expected `bound = \"..\"`", 68 | ARBITRARY_ATTRIBUTE_NAME, 69 | ), 70 | )) 71 | } 72 | } 73 | } 74 | } 75 | 76 | Ok(Self { bounds }) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/foreign/std/net.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, Result, Unstructured}, 3 | std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, 4 | }; 5 | 6 | impl<'a> Arbitrary<'a> for Ipv4Addr { 7 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 8 | Ok(Ipv4Addr::from(u32::arbitrary(u)?)) 9 | } 10 | 11 | #[inline] 12 | fn size_hint(_depth: usize) -> (usize, Option) { 13 | (4, Some(4)) 14 | } 15 | } 16 | 17 | impl<'a> Arbitrary<'a> for Ipv6Addr { 18 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 19 | Ok(Ipv6Addr::from(u128::arbitrary(u)?)) 20 | } 21 | 22 | #[inline] 23 | fn size_hint(_depth: usize) -> (usize, Option) { 24 | (16, Some(16)) 25 | } 26 | } 27 | 28 | impl<'a> Arbitrary<'a> for IpAddr { 29 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 30 | if u.arbitrary()? { 31 | Ok(IpAddr::V4(u.arbitrary()?)) 32 | } else { 33 | Ok(IpAddr::V6(u.arbitrary()?)) 34 | } 35 | } 36 | 37 | fn size_hint(depth: usize) -> (usize, Option) { 38 | size_hint::and( 39 | bool::size_hint(depth), 40 | size_hint::or(Ipv4Addr::size_hint(depth), Ipv6Addr::size_hint(depth)), 41 | ) 42 | } 43 | } 44 | 45 | impl<'a> Arbitrary<'a> for SocketAddrV4 { 46 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 47 | Ok(SocketAddrV4::new(u.arbitrary()?, u.arbitrary()?)) 48 | } 49 | 50 | #[inline] 51 | fn size_hint(depth: usize) -> (usize, Option) { 52 | size_hint::and(Ipv4Addr::size_hint(depth), u16::size_hint(depth)) 53 | } 54 | } 55 | 56 | impl<'a> Arbitrary<'a> for SocketAddrV6 { 57 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 58 | Ok(SocketAddrV6::new( 59 | u.arbitrary()?, 60 | u.arbitrary()?, 61 | u.arbitrary()?, 62 | u.arbitrary()?, 63 | )) 64 | } 65 | 66 | #[inline] 67 | fn size_hint(depth: usize) -> (usize, Option) { 68 | size_hint::and( 69 | Ipv6Addr::size_hint(depth), 70 | size_hint::and( 71 | u16::size_hint(depth), 72 | size_hint::and(u32::size_hint(depth), u32::size_hint(depth)), 73 | ), 74 | ) 75 | } 76 | } 77 | 78 | impl<'a> Arbitrary<'a> for SocketAddr { 79 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 80 | if u.arbitrary()? { 81 | Ok(SocketAddr::V4(u.arbitrary()?)) 82 | } else { 83 | Ok(SocketAddr::V6(u.arbitrary()?)) 84 | } 85 | } 86 | 87 | fn size_hint(depth: usize) -> (usize, Option) { 88 | size_hint::and( 89 | bool::size_hint(depth), 90 | size_hint::or( 91 | SocketAddrV4::size_hint(depth), 92 | SocketAddrV6::size_hint(depth), 93 | ), 94 | ) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/foreign/core/ops.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}, 3 | core::{ 4 | mem, 5 | ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}, 6 | }, 7 | }; 8 | 9 | macro_rules! impl_range { 10 | ( 11 | $range:ty, 12 | $value_closure:expr, 13 | $value_ty:ty, 14 | $fun:ident($fun_closure:expr), 15 | $size_hint_closure:expr 16 | ) => { 17 | impl<'a, A> Arbitrary<'a> for $range 18 | where 19 | A: Arbitrary<'a> + Clone + PartialOrd, 20 | { 21 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 22 | let value: $value_ty = Arbitrary::arbitrary(u)?; 23 | Ok($fun(value, $fun_closure)) 24 | } 25 | 26 | #[inline] 27 | fn size_hint(depth: usize) -> (usize, Option) { 28 | Self::try_size_hint(depth).unwrap_or_default() 29 | } 30 | 31 | #[inline] 32 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 33 | #[allow(clippy::redundant_closure_call)] 34 | $size_hint_closure(depth) 35 | } 36 | } 37 | }; 38 | } 39 | impl_range!( 40 | Range, 41 | |r: &Range| (r.start.clone(), r.end.clone()), 42 | (A, A), 43 | bounded_range(|(a, b)| a..b), 44 | |depth| Ok(crate::size_hint::and( 45 | ::try_size_hint(depth)?, 46 | ::try_size_hint(depth)?, 47 | )) 48 | ); 49 | impl_range!( 50 | RangeFrom, 51 | |r: &RangeFrom| r.start.clone(), 52 | A, 53 | unbounded_range(|a| a..), 54 | |depth| ::try_size_hint(depth) 55 | ); 56 | impl_range!( 57 | RangeInclusive, 58 | |r: &RangeInclusive| (r.start().clone(), r.end().clone()), 59 | (A, A), 60 | bounded_range(|(a, b)| a..=b), 61 | |depth| Ok(crate::size_hint::and( 62 | ::try_size_hint(depth)?, 63 | ::try_size_hint(depth)?, 64 | )) 65 | ); 66 | impl_range!( 67 | RangeTo, 68 | |r: &RangeTo| r.end.clone(), 69 | A, 70 | unbounded_range(|b| ..b), 71 | |depth| ::try_size_hint(depth) 72 | ); 73 | impl_range!( 74 | RangeToInclusive, 75 | |r: &RangeToInclusive| r.end.clone(), 76 | A, 77 | unbounded_range(|b| ..=b), 78 | |depth| ::try_size_hint(depth) 79 | ); 80 | 81 | pub(crate) fn bounded_range(bounds: (I, I), cb: CB) -> R 82 | where 83 | CB: Fn((I, I)) -> R, 84 | I: PartialOrd, 85 | R: RangeBounds, 86 | { 87 | let (mut start, mut end) = bounds; 88 | if start > end { 89 | mem::swap(&mut start, &mut end); 90 | } 91 | cb((start, end)) 92 | } 93 | 94 | pub(crate) fn unbounded_range(bound: I, cb: CB) -> R 95 | where 96 | CB: Fn(I) -> R, 97 | R: RangeBounds, 98 | { 99 | cb(bound) 100 | } 101 | 102 | impl<'a, A> Arbitrary<'a> for Bound 103 | where 104 | A: Arbitrary<'a>, 105 | { 106 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 107 | match u.int_in_range::(0..=2)? { 108 | 0 => Ok(Bound::Included(A::arbitrary(u)?)), 109 | 1 => Ok(Bound::Excluded(A::arbitrary(u)?)), 110 | 2 => Ok(Bound::Unbounded), 111 | _ => unreachable!(), 112 | } 113 | } 114 | 115 | #[inline] 116 | fn size_hint(depth: usize) -> (usize, Option) { 117 | Self::try_size_hint(depth).unwrap_or_default() 118 | } 119 | 120 | #[inline] 121 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 122 | Ok(size_hint::or( 123 | size_hint::and((1, Some(1)), A::try_size_hint(depth)?), 124 | (1, Some(1)), 125 | )) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /derive/src/field_attributes.rs: -------------------------------------------------------------------------------- 1 | use crate::ARBITRARY_ATTRIBUTE_NAME; 2 | use proc_macro2::{Span, TokenStream, TokenTree}; 3 | use quote::quote; 4 | use syn::{spanned::Spanned, *}; 5 | 6 | /// Determines how a value for a field should be constructed. 7 | #[cfg_attr(test, derive(Debug))] 8 | pub enum FieldConstructor { 9 | /// Assume that Arbitrary is defined for the type of this field and use it (default) 10 | Arbitrary, 11 | 12 | /// Places `Default::default()` as a field value. 13 | Default, 14 | 15 | /// Use custom function or closure to generate a value for a field. 16 | With(TokenStream), 17 | 18 | /// Set a field always to the given value. 19 | Value(TokenStream), 20 | } 21 | 22 | pub fn determine_field_constructor(field: &Field) -> Result { 23 | let opt_attr = fetch_attr_from_field(field)?; 24 | let ctor = match opt_attr { 25 | Some(attr) => parse_attribute(attr)?, 26 | None => FieldConstructor::Arbitrary, 27 | }; 28 | Ok(ctor) 29 | } 30 | 31 | fn fetch_attr_from_field(field: &Field) -> Result> { 32 | let found_attributes: Vec<_> = field 33 | .attrs 34 | .iter() 35 | .filter(|a| { 36 | let path = a.path(); 37 | let name = quote!(#path).to_string(); 38 | name == ARBITRARY_ATTRIBUTE_NAME 39 | }) 40 | .collect(); 41 | if found_attributes.len() > 1 { 42 | let name = field.ident.as_ref().unwrap(); 43 | let msg = format!( 44 | "Multiple conflicting #[{ARBITRARY_ATTRIBUTE_NAME}] attributes found on field `{name}`" 45 | ); 46 | return Err(syn::Error::new(field.span(), msg)); 47 | } 48 | Ok(found_attributes.into_iter().next()) 49 | } 50 | 51 | fn parse_attribute(attr: &Attribute) -> Result { 52 | if let Meta::List(ref meta_list) = attr.meta { 53 | parse_attribute_internals(meta_list) 54 | } else { 55 | let msg = format!("#[{ARBITRARY_ATTRIBUTE_NAME}] must contain a group"); 56 | Err(syn::Error::new(attr.span(), msg)) 57 | } 58 | } 59 | 60 | fn parse_attribute_internals(meta_list: &MetaList) -> Result { 61 | let mut tokens_iter = meta_list.tokens.clone().into_iter(); 62 | let token = tokens_iter.next().ok_or_else(|| { 63 | let msg = format!("#[{ARBITRARY_ATTRIBUTE_NAME}] cannot be empty."); 64 | syn::Error::new(meta_list.span(), msg) 65 | })?; 66 | match token.to_string().as_ref() { 67 | "default" => Ok(FieldConstructor::Default), 68 | "with" => { 69 | let func_path = parse_assigned_value("with", tokens_iter, meta_list.span())?; 70 | Ok(FieldConstructor::With(func_path)) 71 | } 72 | "value" => { 73 | let value = parse_assigned_value("value", tokens_iter, meta_list.span())?; 74 | Ok(FieldConstructor::Value(value)) 75 | } 76 | _ => { 77 | let msg = format!("Unknown option for #[{ARBITRARY_ATTRIBUTE_NAME}]: `{token}`"); 78 | Err(syn::Error::new(token.span(), msg)) 79 | } 80 | } 81 | } 82 | 83 | // Input: 84 | // = 2 + 2 85 | // Output: 86 | // 2 + 2 87 | fn parse_assigned_value( 88 | opt_name: &str, 89 | mut tokens_iter: impl Iterator, 90 | default_span: Span, 91 | ) -> Result { 92 | let eq_sign = tokens_iter.next().ok_or_else(|| { 93 | let msg = format!( 94 | "Invalid syntax for #[{ARBITRARY_ATTRIBUTE_NAME}], `{opt_name}` is missing assignment." 95 | ); 96 | syn::Error::new(default_span, msg) 97 | })?; 98 | 99 | if eq_sign.to_string() == "=" { 100 | Ok(tokens_iter.collect()) 101 | } else { 102 | let msg = format!("Invalid syntax for #[{ARBITRARY_ATTRIBUTE_NAME}], expected `=` after `{opt_name}`, got: `{eq_sign}`"); 103 | Err(syn::Error::new(eq_sign.span(), msg)) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/bound.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "derive")] 2 | 3 | use arbitrary::{Arbitrary, Unstructured}; 4 | 5 | fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T { 6 | let mut buf = Unstructured::new(input); 7 | T::arbitrary(&mut buf).expect("can create arbitrary instance OK") 8 | } 9 | 10 | /// This wrapper trait *implies* `Arbitrary`, but the compiler isn't smart enough to work that out 11 | /// so when using this wrapper we *must* opt-out of the auto-generated `T: Arbitrary` bounds. 12 | pub trait WrapperTrait: for<'a> Arbitrary<'a> {} 13 | 14 | impl WrapperTrait for u32 {} 15 | 16 | #[derive(Arbitrary)] 17 | #[arbitrary(bound = "T: WrapperTrait")] 18 | struct GenericSingleBound { 19 | t: T, 20 | } 21 | 22 | #[test] 23 | fn single_bound() { 24 | let v: GenericSingleBound = arbitrary_from(&[0, 0, 0, 0]); 25 | assert_eq!(v.t, 0); 26 | } 27 | 28 | #[derive(Arbitrary)] 29 | #[arbitrary(bound = "T: WrapperTrait, U: WrapperTrait")] 30 | struct GenericMultipleBoundsSingleAttribute { 31 | t: T, 32 | u: U, 33 | } 34 | 35 | #[test] 36 | fn multiple_bounds_single_attribute() { 37 | let v: GenericMultipleBoundsSingleAttribute = 38 | arbitrary_from(&[1, 0, 0, 0, 2, 0, 0, 0]); 39 | assert_eq!(v.t, 1); 40 | assert_eq!(v.u, 2); 41 | } 42 | 43 | #[derive(Arbitrary)] 44 | #[arbitrary(bound = "T: WrapperTrait")] 45 | #[arbitrary(bound = "U: Default")] 46 | struct GenericMultipleArbitraryAttributes { 47 | t: T, 48 | #[arbitrary(default)] 49 | u: U, 50 | } 51 | 52 | #[test] 53 | fn multiple_arbitrary_attributes() { 54 | let v: GenericMultipleArbitraryAttributes = arbitrary_from(&[1, 0, 0, 0]); 55 | assert_eq!(v.t, 1); 56 | assert_eq!(v.u, 0); 57 | } 58 | 59 | #[derive(Arbitrary)] 60 | #[arbitrary(bound = "T: WrapperTrait", bound = "U: Default")] 61 | struct GenericMultipleBoundAttributes { 62 | t: T, 63 | #[arbitrary(default)] 64 | u: U, 65 | } 66 | 67 | #[test] 68 | fn multiple_bound_attributes() { 69 | let v: GenericMultipleBoundAttributes = arbitrary_from(&[1, 0, 0, 0]); 70 | assert_eq!(v.t, 1); 71 | assert_eq!(v.u, 0); 72 | } 73 | 74 | #[derive(Arbitrary)] 75 | #[arbitrary(bound = "T: WrapperTrait", bound = "U: Default")] 76 | #[arbitrary(bound = "V: WrapperTrait, W: Default")] 77 | struct GenericMultipleArbitraryAndBoundAttributes< 78 | T: WrapperTrait, 79 | U: Default, 80 | V: WrapperTrait, 81 | W: Default, 82 | > { 83 | t: T, 84 | #[arbitrary(default)] 85 | u: U, 86 | v: V, 87 | #[arbitrary(default)] 88 | w: W, 89 | } 90 | 91 | #[test] 92 | fn multiple_arbitrary_and_bound_attributes() { 93 | let v: GenericMultipleArbitraryAndBoundAttributes = 94 | arbitrary_from(&[1, 0, 0, 0, 2, 0, 0, 0]); 95 | assert_eq!(v.t, 1); 96 | assert_eq!(v.u, 0); 97 | assert_eq!(v.v, 2); 98 | assert_eq!(v.w, 0); 99 | } 100 | 101 | #[derive(Arbitrary)] 102 | #[arbitrary(bound = "T: Default")] 103 | struct GenericDefault { 104 | #[arbitrary(default)] 105 | x: T, 106 | } 107 | 108 | #[test] 109 | fn default_bound() { 110 | // We can write a generic func without any `Arbitrary` bound. 111 | fn generic_default() -> GenericDefault { 112 | arbitrary_from(&[]) 113 | } 114 | 115 | assert_eq!(generic_default::().x, 0); 116 | assert_eq!(generic_default::().x, String::new()); 117 | assert_eq!(generic_default::>().x, Vec::new()); 118 | } 119 | 120 | #[derive(Arbitrary)] 121 | #[arbitrary()] 122 | struct EmptyArbitraryAttribute { 123 | t: u32, 124 | } 125 | 126 | #[test] 127 | fn empty_arbitrary_attribute() { 128 | let v: EmptyArbitraryAttribute = arbitrary_from(&[1, 0, 0, 0]); 129 | assert_eq!(v.t, 1); 130 | } 131 | 132 | #[derive(Arbitrary)] 133 | #[arbitrary(bound = "")] 134 | struct EmptyBoundAttribute { 135 | t: u32, 136 | } 137 | 138 | #[test] 139 | fn empty_bound_attribute() { 140 | let v: EmptyBoundAttribute = arbitrary_from(&[1, 0, 0, 0]); 141 | assert_eq!(v.t, 1); 142 | } 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Arbitrary

4 | 5 |

The trait for generating structured data from arbitrary, unstructured input.

6 | 7 | GitHub Actions Status 8 | 9 |
10 | 11 | ## About 12 | 13 | The `Arbitrary` crate lets you construct arbitrary instances of a type. 14 | 15 | This crate is primarily intended to be combined with a fuzzer like [libFuzzer 16 | and `cargo-fuzz`](https://github.com/rust-fuzz/cargo-fuzz) or 17 | [AFL](https://github.com/rust-fuzz/afl.rs), and to help you turn the raw, 18 | untyped byte buffers that they produce into well-typed, valid, structured 19 | values. This allows you to combine structure-aware test case generation with 20 | coverage-guided, mutation-based fuzzers. 21 | 22 | ## Documentation 23 | 24 | [**Read the API documentation on `docs.rs`!**](https://docs.rs/arbitrary) 25 | 26 | ## Example 27 | 28 | Say you're writing a color conversion library, and you have an `Rgb` struct to 29 | represent RGB colors. You might want to implement `Arbitrary` for `Rgb` so that 30 | you could take arbitrary `Rgb` instances in a test function that asserts some 31 | property (for example, asserting that RGB converted to HSL and converted back to 32 | RGB always ends up exactly where we started). 33 | 34 | ### Automatically Deriving `Arbitrary` 35 | 36 | Automatically deriving the `Arbitrary` trait is the recommended way to implement 37 | `Arbitrary` for your types. 38 | 39 | Automatically deriving `Arbitrary` requires you to enable the `"derive"` cargo 40 | feature: 41 | 42 | ```toml 43 | # Cargo.toml 44 | 45 | [dependencies] 46 | arbitrary = { version = "1", features = ["derive"] } 47 | ``` 48 | 49 | And then you can simply add `#[derive(Arbitrary)]` annotations to your types: 50 | 51 | ```rust 52 | // rgb.rs 53 | 54 | use arbitrary::Arbitrary; 55 | 56 | #[derive(Arbitrary)] 57 | pub struct Rgb { 58 | pub r: u8, 59 | pub g: u8, 60 | pub b: u8, 61 | } 62 | ``` 63 | 64 | #### Customizing single fields 65 | 66 | This can be particular handy if your structure uses a type that does not implement `Arbitrary` or you want to have more customization for particular fields. 67 | 68 | ```rust 69 | #[derive(Arbitrary)] 70 | pub struct Rgba { 71 | // set `r` to Default::default() 72 | #[arbitrary(default)] 73 | pub r: u8, 74 | 75 | // set `g` to 255 76 | #[arbitrary(value = 255)] 77 | pub g: u8, 78 | 79 | // Generate `b` with a custom function of type 80 | // 81 | // fn(&mut Unstructured) -> arbitrary::Result 82 | // 83 | // where `T` is the field's type. 84 | #[arbitrary(with = arbitrary_b)] 85 | pub b: u8, 86 | 87 | // Generate `a` with a custom closure (shortcut to avoid a custom function) 88 | #[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=64))] 89 | pub a: u8, 90 | } 91 | 92 | fn arbitrary_b(u: &mut Unstructured) -> arbitrary::Result { 93 | u.int_in_range(64..=128) 94 | } 95 | ``` 96 | 97 | ### Implementing `Arbitrary` By Hand 98 | 99 | Alternatively, you can write an `Arbitrary` implementation by hand: 100 | 101 | ```rust 102 | // rgb.rs 103 | 104 | use arbitrary::{Arbitrary, Result, Unstructured}; 105 | 106 | #[derive(Copy, Clone, Debug)] 107 | pub struct Rgb { 108 | pub r: u8, 109 | pub g: u8, 110 | pub b: u8, 111 | } 112 | 113 | impl<'a> Arbitrary<'a> for Rgb { 114 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 115 | let r = u8::arbitrary(u)?; 116 | let g = u8::arbitrary(u)?; 117 | let b = u8::arbitrary(u)?; 118 | Ok(Rgb { r, g, b }) 119 | } 120 | } 121 | ``` 122 | 123 | ## Minimum Supported Rust Version (MSRV) 124 | 125 | 126 | 127 | This crate is guaranteed to compile on stable Rust **1.63.0** and up. It might 128 | compile with older versions but that may change in any new patch release. 129 | 130 | We reserve the right to increment the MSRV on minor releases, however we will 131 | strive to only do it deliberately and for good reasons. 132 | 133 | ## License 134 | 135 | Licensed under dual MIT or Apache-2.0 at your choice. 136 | 137 | Unless you explicitly state otherwise, any contribution intentionally submitted 138 | for inclusion in this project by you, as defined in the Apache-2.0 license, 139 | shall be dual licensed as above, without any additional terms or conditions. 140 | -------------------------------------------------------------------------------- /src/foreign/core/num.rs: -------------------------------------------------------------------------------- 1 | use { 2 | crate::{Arbitrary, MaxRecursionReached, Result, Unstructured}, 3 | core::{ 4 | mem, 5 | num::{ 6 | NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, 7 | NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, 8 | }, 9 | }, 10 | }; 11 | 12 | macro_rules! impl_arbitrary_for_integers { 13 | ( $( $ty:ty; )* ) => { 14 | $( 15 | impl<'a> Arbitrary<'a> for $ty { 16 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 17 | let mut buf = [0; mem::size_of::<$ty>()]; 18 | u.fill_buffer(&mut buf)?; 19 | Ok(Self::from_le_bytes(buf)) 20 | } 21 | 22 | #[inline] 23 | fn size_hint(_depth: usize) -> (usize, Option) { 24 | let n = mem::size_of::<$ty>(); 25 | (n, Some(n)) 26 | } 27 | 28 | } 29 | )* 30 | } 31 | } 32 | 33 | impl_arbitrary_for_integers! { 34 | u8; 35 | u16; 36 | u32; 37 | u64; 38 | u128; 39 | i8; 40 | i16; 41 | i32; 42 | i64; 43 | i128; 44 | } 45 | 46 | // Note: We forward Arbitrary for i/usize to i/u64 in order to simplify corpus 47 | // compatibility between 32-bit and 64-bit builds. This introduces dead space in 48 | // 32-bit builds but keeps the input layout independent of the build platform. 49 | impl<'a> Arbitrary<'a> for usize { 50 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 51 | u.arbitrary::().map(|x| x as usize) 52 | } 53 | 54 | #[inline] 55 | fn size_hint(depth: usize) -> (usize, Option) { 56 | ::size_hint(depth) 57 | } 58 | } 59 | 60 | impl<'a> Arbitrary<'a> for isize { 61 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 62 | u.arbitrary::().map(|x| x as isize) 63 | } 64 | 65 | #[inline] 66 | fn size_hint(depth: usize) -> (usize, Option) { 67 | ::size_hint(depth) 68 | } 69 | } 70 | 71 | macro_rules! impl_arbitrary_for_floats { 72 | ( $( $ty:ident : $unsigned:ty; )* ) => { 73 | $( 74 | impl<'a> Arbitrary<'a> for $ty { 75 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 76 | Ok(Self::from_bits(<$unsigned as Arbitrary<'a>>::arbitrary(u)?)) 77 | } 78 | 79 | #[inline] 80 | fn size_hint(depth: usize) -> (usize, Option) { 81 | <$unsigned as Arbitrary<'a>>::size_hint(depth) 82 | } 83 | } 84 | )* 85 | } 86 | } 87 | 88 | impl_arbitrary_for_floats! { 89 | f32: u32; 90 | f64: u64; 91 | } 92 | 93 | macro_rules! implement_nonzero_int { 94 | ($nonzero:ty, $int:ty) => { 95 | impl<'a> Arbitrary<'a> for $nonzero { 96 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 97 | match Self::new(<$int as Arbitrary<'a>>::arbitrary(u)?) { 98 | Some(n) => Ok(n), 99 | None => Ok(Self::new(<$int>::MAX).unwrap()), 100 | } 101 | } 102 | 103 | #[inline] 104 | fn size_hint(depth: usize) -> (usize, Option) { 105 | <$int as Arbitrary<'a>>::size_hint(depth) 106 | } 107 | } 108 | }; 109 | } 110 | 111 | implement_nonzero_int! { NonZeroI8, i8 } 112 | implement_nonzero_int! { NonZeroI16, i16 } 113 | implement_nonzero_int! { NonZeroI32, i32 } 114 | implement_nonzero_int! { NonZeroI64, i64 } 115 | implement_nonzero_int! { NonZeroI128, i128 } 116 | implement_nonzero_int! { NonZeroIsize, isize } 117 | implement_nonzero_int! { NonZeroU8, u8 } 118 | implement_nonzero_int! { NonZeroU16, u16 } 119 | implement_nonzero_int! { NonZeroU32, u32 } 120 | implement_nonzero_int! { NonZeroU64, u64 } 121 | implement_nonzero_int! { NonZeroU128, u128 } 122 | implement_nonzero_int! { NonZeroUsize, usize } 123 | 124 | impl<'a, A> Arbitrary<'a> for Wrapping
125 | where 126 | A: Arbitrary<'a>, 127 | { 128 | fn arbitrary(u: &mut Unstructured<'a>) -> Result { 129 | Arbitrary::arbitrary(u).map(Wrapping) 130 | } 131 | 132 | #[inline] 133 | fn size_hint(depth: usize) -> (usize, Option) { 134 | Self::try_size_hint(depth).unwrap_or_default() 135 | } 136 | 137 | #[inline] 138 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 139 | >::try_size_hint(depth) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/size_hint.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for working with and combining the results of 2 | //! [`Arbitrary::size_hint`][crate::Arbitrary::size_hint]. 3 | 4 | pub(crate) const MAX_DEPTH: usize = 20; 5 | 6 | /// Protects against potential infinite recursion when calculating size hints 7 | /// due to indirect type recursion. 8 | /// 9 | /// When the depth is not too deep, calls `f` with `depth + 1` to calculate the 10 | /// size hint. 11 | /// 12 | /// Otherwise, returns the default size hint: `(0, None)`. 13 | /// 14 | /// 15 | #[inline] 16 | #[deprecated(note = "use `try_recursion_guard` instead")] 17 | pub fn recursion_guard( 18 | depth: usize, 19 | f: impl FnOnce(usize) -> (usize, Option), 20 | ) -> (usize, Option) { 21 | if depth > MAX_DEPTH { 22 | (0, None) 23 | } else { 24 | f(depth + 1) 25 | } 26 | } 27 | 28 | /// Protects against potential infinite recursion when calculating size hints 29 | /// due to indirect type recursion. 30 | /// 31 | /// When the depth is not too deep, calls `f` with `depth + 1` to calculate the 32 | /// size hint. 33 | /// 34 | /// Otherwise, returns an error. 35 | /// 36 | /// This should be used when implementing [`try_size_hint`](crate::Arbitrary::try_size_hint) 37 | #[inline] 38 | pub fn try_recursion_guard( 39 | depth: usize, 40 | f: impl FnOnce(usize) -> Result<(usize, Option), crate::MaxRecursionReached>, 41 | ) -> Result<(usize, Option), crate::MaxRecursionReached> { 42 | if depth > MAX_DEPTH { 43 | Err(crate::MaxRecursionReached {}) 44 | } else { 45 | f(depth + 1) 46 | } 47 | } 48 | 49 | /// Take the sum of the `lhs` and `rhs` size hints. 50 | #[inline] 51 | pub fn and(lhs: (usize, Option), rhs: (usize, Option)) -> (usize, Option) { 52 | let lower = lhs.0 + rhs.0; 53 | let upper = lhs.1.and_then(|lhs| rhs.1.map(|rhs| lhs + rhs)); 54 | (lower, upper) 55 | } 56 | 57 | /// Take the sum of all of the given size hints. 58 | /// 59 | /// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming 60 | /// nothing. 61 | #[inline] 62 | pub fn and_all(hints: &[(usize, Option)]) -> (usize, Option) { 63 | hints.iter().copied().fold((0, Some(0)), and) 64 | } 65 | 66 | /// Take the minimum of the lower bounds and maximum of the upper bounds in the 67 | /// `lhs` and `rhs` size hints. 68 | #[inline] 69 | pub fn or(lhs: (usize, Option), rhs: (usize, Option)) -> (usize, Option) { 70 | let lower = std::cmp::min(lhs.0, rhs.0); 71 | let upper = lhs 72 | .1 73 | .and_then(|lhs| rhs.1.map(|rhs| std::cmp::max(lhs, rhs))); 74 | (lower, upper) 75 | } 76 | 77 | /// Take the maximum of the `lhs` and `rhs` size hints. 78 | /// 79 | /// If `hints` is empty, returns `(0, Some(0))`, aka the size of consuming 80 | /// nothing. 81 | #[inline] 82 | pub fn or_all(hints: &[(usize, Option)]) -> (usize, Option) { 83 | if let Some(head) = hints.first().copied() { 84 | hints[1..].iter().copied().fold(head, or) 85 | } else { 86 | (0, Some(0)) 87 | } 88 | } 89 | 90 | #[cfg(test)] 91 | mod tests { 92 | #[test] 93 | fn and() { 94 | assert_eq!((5, Some(5)), super::and((2, Some(2)), (3, Some(3)))); 95 | assert_eq!((5, None), super::and((2, Some(2)), (3, None))); 96 | assert_eq!((5, None), super::and((2, None), (3, Some(3)))); 97 | assert_eq!((5, None), super::and((2, None), (3, None))); 98 | } 99 | 100 | #[test] 101 | fn or() { 102 | assert_eq!((2, Some(3)), super::or((2, Some(2)), (3, Some(3)))); 103 | assert_eq!((2, None), super::or((2, Some(2)), (3, None))); 104 | assert_eq!((2, None), super::or((2, None), (3, Some(3)))); 105 | assert_eq!((2, None), super::or((2, None), (3, None))); 106 | } 107 | 108 | #[test] 109 | fn and_all() { 110 | assert_eq!((0, Some(0)), super::and_all(&[])); 111 | assert_eq!( 112 | (7, Some(7)), 113 | super::and_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))]) 114 | ); 115 | assert_eq!( 116 | (7, None), 117 | super::and_all(&[(1, Some(1)), (2, Some(2)), (4, None)]) 118 | ); 119 | assert_eq!( 120 | (7, None), 121 | super::and_all(&[(1, Some(1)), (2, None), (4, Some(4))]) 122 | ); 123 | assert_eq!( 124 | (7, None), 125 | super::and_all(&[(1, None), (2, Some(2)), (4, Some(4))]) 126 | ); 127 | } 128 | 129 | #[test] 130 | fn or_all() { 131 | assert_eq!((0, Some(0)), super::or_all(&[])); 132 | assert_eq!( 133 | (1, Some(4)), 134 | super::or_all(&[(1, Some(1)), (2, Some(2)), (4, Some(4))]) 135 | ); 136 | assert_eq!( 137 | (1, None), 138 | super::or_all(&[(1, Some(1)), (2, Some(2)), (4, None)]) 139 | ); 140 | assert_eq!( 141 | (1, None), 142 | super::or_all(&[(1, Some(1)), (2, None), (4, Some(4))]) 143 | ); 144 | assert_eq!( 145 | (1, None), 146 | super::or_all(&[(1, None), (2, Some(2)), (4, Some(4))]) 147 | ); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use { 2 | super::{Arbitrary, Result, Unstructured}, 3 | std::{collections::HashSet, fmt::Debug, hash::Hash, rc::Rc, sync::Arc}, 4 | }; 5 | 6 | /// Assert that the given expected values are all generated. 7 | /// 8 | /// Exhaustively enumerates all buffers up to length 10 containing the 9 | /// following bytes: `0x00`, `0x01`, `0x61` (aka ASCII 'a'), and `0xff` 10 | fn assert_generates(expected_values: impl IntoIterator) 11 | where 12 | T: Clone + Debug + Hash + Eq + for<'a> Arbitrary<'a>, 13 | { 14 | let expected_values: HashSet<_> = expected_values.into_iter().collect(); 15 | let mut arbitrary_expected = expected_values.clone(); 16 | let mut arbitrary_take_rest_expected = expected_values; 17 | 18 | let bytes = [0, 1, b'a', 0xff]; 19 | let max_len = 10; 20 | 21 | let mut buf = Vec::with_capacity(max_len); 22 | 23 | let mut g = exhaustigen::Gen::new(); 24 | while !g.done() { 25 | let len = g.gen(max_len); 26 | 27 | buf.clear(); 28 | buf.extend( 29 | std::iter::repeat_with(|| { 30 | let index = g.gen(bytes.len() - 1); 31 | bytes[index] 32 | }) 33 | .take(len), 34 | ); 35 | 36 | let mut u = Unstructured::new(&buf); 37 | let val = T::arbitrary(&mut u).unwrap(); 38 | arbitrary_expected.remove(&val); 39 | 40 | let u = Unstructured::new(&buf); 41 | let val = T::arbitrary_take_rest(u).unwrap(); 42 | arbitrary_take_rest_expected.remove(&val); 43 | 44 | if arbitrary_expected.is_empty() && arbitrary_take_rest_expected.is_empty() { 45 | return; 46 | } 47 | } 48 | 49 | panic!( 50 | "failed to generate all expected values!\n\n\ 51 | T::arbitrary did not generate: {arbitrary_expected:#?}\n\n\ 52 | T::arbitrary_take_rest did not generate {arbitrary_take_rest_expected:#?}" 53 | ) 54 | } 55 | 56 | /// Generates an arbitrary `T`, and checks that the result is consistent with the 57 | /// `size_hint()` reported by `T`. 58 | fn checked_arbitrary<'a, T: Arbitrary<'a>>(u: &mut Unstructured<'a>) -> Result { 59 | let (min, max) = T::size_hint(0); 60 | 61 | let len_before = u.len(); 62 | let result = T::arbitrary(u); 63 | 64 | let consumed = len_before - u.len(); 65 | 66 | if let Some(max) = max { 67 | assert!( 68 | consumed <= max, 69 | "incorrect maximum size: indicated {}, actually consumed {}", 70 | max, 71 | consumed 72 | ); 73 | } 74 | 75 | if result.is_ok() { 76 | assert!( 77 | consumed >= min, 78 | "incorrect minimum size: indicated {}, actually consumed {}", 79 | min, 80 | consumed 81 | ); 82 | } 83 | 84 | result 85 | } 86 | 87 | /// Like `checked_arbitrary()`, but calls `arbitrary_take_rest()` instead of `arbitrary()`. 88 | fn checked_arbitrary_take_rest<'a, T: Arbitrary<'a>>(u: Unstructured<'a>) -> Result { 89 | let (min, _) = T::size_hint(0); 90 | 91 | let len_before = u.len(); 92 | let result = T::arbitrary_take_rest(u); 93 | 94 | if result.is_ok() { 95 | assert!( 96 | len_before >= min, 97 | "incorrect minimum size: indicated {}, worked with {}", 98 | min, 99 | len_before 100 | ); 101 | } 102 | 103 | result 104 | } 105 | 106 | #[test] 107 | fn finite_buffer_fill_buffer() { 108 | let x = [1, 2, 3, 4]; 109 | let mut rb = Unstructured::new(&x); 110 | let mut z = [0; 2]; 111 | rb.fill_buffer(&mut z).unwrap(); 112 | assert_eq!(z, [1, 2]); 113 | rb.fill_buffer(&mut z).unwrap(); 114 | assert_eq!(z, [3, 4]); 115 | rb.fill_buffer(&mut z).unwrap(); 116 | assert_eq!(z, [0, 0]); 117 | } 118 | 119 | #[test] 120 | fn arbitrary_for_integers() { 121 | let x = [1, 2, 3, 4]; 122 | let mut buf = Unstructured::new(&x); 123 | let expected = 1 | (2 << 8) | (3 << 16) | (4 << 24); 124 | let actual = checked_arbitrary::(&mut buf).unwrap(); 125 | assert_eq!(expected, actual); 126 | 127 | assert_generates([ 128 | i32::from_ne_bytes([0, 0, 0, 0]), 129 | i32::from_ne_bytes([0, 0, 0, 1]), 130 | i32::from_ne_bytes([0, 0, 1, 0]), 131 | i32::from_ne_bytes([0, 1, 0, 0]), 132 | i32::from_ne_bytes([1, 0, 0, 0]), 133 | i32::from_ne_bytes([1, 1, 1, 1]), 134 | i32::from_ne_bytes([0xff, 0xff, 0xff, 0xff]), 135 | ]); 136 | } 137 | 138 | #[test] 139 | fn arbitrary_for_bytes() { 140 | let x = [1, 2, 3, 4, 4]; 141 | let mut buf = Unstructured::new(&x); 142 | let expected = &[1, 2, 3, 4]; 143 | let actual = checked_arbitrary::<&[u8]>(&mut buf).unwrap(); 144 | assert_eq!(expected, actual); 145 | } 146 | 147 | #[test] 148 | fn arbitrary_take_rest_for_bytes() { 149 | let x = [1, 2, 3, 4]; 150 | let buf = Unstructured::new(&x); 151 | let expected = &[1, 2, 3, 4]; 152 | let actual = checked_arbitrary_take_rest::<&[u8]>(buf).unwrap(); 153 | assert_eq!(expected, actual); 154 | } 155 | 156 | #[test] 157 | fn arbitrary_for_vec_u8() { 158 | assert_generates::>([ 159 | vec![], 160 | vec![0], 161 | vec![1], 162 | vec![0, 0], 163 | vec![0, 1], 164 | vec![1, 0], 165 | vec![1, 1], 166 | vec![0, 0, 0], 167 | vec![0, 0, 1], 168 | vec![0, 1, 0], 169 | vec![0, 1, 1], 170 | vec![1, 0, 0], 171 | vec![1, 0, 1], 172 | vec![1, 1, 0], 173 | vec![1, 1, 1], 174 | ]); 175 | } 176 | 177 | #[test] 178 | fn arbitrary_for_vec_vec_u8() { 179 | assert_generates::>>([ 180 | vec![], 181 | vec![vec![]], 182 | vec![vec![0]], 183 | vec![vec![1]], 184 | vec![vec![0, 1]], 185 | vec![vec![], vec![]], 186 | vec![vec![0], vec![]], 187 | vec![vec![], vec![1]], 188 | vec![vec![0], vec![1]], 189 | vec![vec![0, 1], vec![]], 190 | vec![vec![], vec![1, 0]], 191 | vec![vec![], vec![], vec![]], 192 | ]); 193 | } 194 | 195 | #[test] 196 | fn arbitrary_for_vec_vec_vec_u8() { 197 | assert_generates::>>>([ 198 | vec![], 199 | vec![vec![]], 200 | vec![vec![vec![0]]], 201 | vec![vec![vec![1]]], 202 | vec![vec![vec![0, 1]]], 203 | vec![vec![], vec![]], 204 | vec![vec![], vec![vec![]]], 205 | vec![vec![vec![]], vec![]], 206 | vec![vec![vec![]], vec![vec![]]], 207 | vec![vec![vec![0]], vec![]], 208 | vec![vec![], vec![vec![1]]], 209 | vec![vec![vec![0]], vec![vec![1]]], 210 | vec![vec![vec![0, 1]], vec![]], 211 | vec![vec![], vec![vec![0, 1]]], 212 | vec![vec![], vec![], vec![]], 213 | vec![vec![vec![]], vec![], vec![]], 214 | vec![vec![], vec![vec![]], vec![]], 215 | vec![vec![], vec![], vec![vec![]]], 216 | ]); 217 | } 218 | 219 | #[test] 220 | fn arbitrary_for_string() { 221 | assert_generates::(["".into(), "a".into(), "aa".into(), "aaa".into()]); 222 | } 223 | 224 | #[test] 225 | fn arbitrary_collection() { 226 | let x = [ 227 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 12, 228 | ]; 229 | assert_eq!( 230 | checked_arbitrary::<&[u8]>(&mut Unstructured::new(&x)).unwrap(), 231 | &[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3] 232 | ); 233 | assert_eq!( 234 | checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 235 | &[2, 4, 6, 8, 1] 236 | ); 237 | assert_eq!( 238 | &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 239 | &[2, 4, 6, 8, 1] 240 | ); 241 | assert_eq!( 242 | &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 243 | &[2, 4, 6, 8, 1] 244 | ); 245 | assert_eq!( 246 | &*checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 247 | &[2, 4, 6, 8, 1] 248 | ); 249 | assert_eq!( 250 | checked_arbitrary::>(&mut Unstructured::new(&x)).unwrap(), 251 | &[84148994] 252 | ); 253 | assert_eq!( 254 | checked_arbitrary::(&mut Unstructured::new(&x)).unwrap(), 255 | "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x01\x02\x03" 256 | ); 257 | } 258 | 259 | #[test] 260 | fn arbitrary_take_rest() { 261 | // Basic examples 262 | let x = [1, 2, 3, 4]; 263 | assert_eq!( 264 | checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&x)).unwrap(), 265 | &[1, 2, 3, 4] 266 | ); 267 | assert_eq!( 268 | checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 269 | &[2, 4] 270 | ); 271 | assert_eq!( 272 | &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 273 | &[2, 4] 274 | ); 275 | assert_eq!( 276 | &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 277 | &[2, 4] 278 | ); 279 | assert_eq!( 280 | &*checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 281 | &[2, 4] 282 | ); 283 | assert_eq!( 284 | checked_arbitrary_take_rest::>(Unstructured::new(&x)).unwrap(), 285 | &[0x040302] 286 | ); 287 | assert_eq!( 288 | checked_arbitrary_take_rest::(Unstructured::new(&x)).unwrap(), 289 | "\x01\x02\x03\x04" 290 | ); 291 | 292 | // Empty remainder 293 | assert_eq!( 294 | checked_arbitrary_take_rest::<&[u8]>(Unstructured::new(&[])).unwrap(), 295 | &[] 296 | ); 297 | assert_eq!( 298 | checked_arbitrary_take_rest::>(Unstructured::new(&[])).unwrap(), 299 | &[] 300 | ); 301 | 302 | // Cannot consume all but can consume part of the input 303 | assert_eq!( 304 | checked_arbitrary_take_rest::(Unstructured::new(&[1, 0xFF, 2])).unwrap(), 305 | "\x01" 306 | ); 307 | } 308 | 309 | #[test] 310 | fn size_hint_for_tuples() { 311 | assert_eq!( 312 | (7, Some(7)), 313 | <(bool, u16, i32) as Arbitrary<'_>>::size_hint(0) 314 | ); 315 | assert_eq!((1, None), <(u8, Vec) as Arbitrary>::size_hint(0)); 316 | } 317 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /derive/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /tests/derive.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "derive")] 2 | // Various structs/fields that we are deriving `Arbitrary` for aren't actually 3 | // used except to exercise the derive. 4 | #![allow(dead_code)] 5 | // Various assert_eq! are used to compare result of bool amongst other data types 6 | // In this case, using assert! is less explicit and readable 7 | #![allow(clippy::bool_assert_comparison)] 8 | 9 | use arbitrary::*; 10 | 11 | fn arbitrary_from<'a, T: Arbitrary<'a>>(input: &'a [u8]) -> T { 12 | let mut buf = Unstructured::new(input); 13 | T::arbitrary(&mut buf).expect("can create arbitrary instance OK") 14 | } 15 | 16 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Arbitrary)] 17 | pub struct Rgb { 18 | pub r: u8, 19 | pub g: u8, 20 | pub b: u8, 21 | } 22 | 23 | #[test] 24 | fn struct_with_named_fields() { 25 | let rgb: Rgb = arbitrary_from(&[4, 5, 6]); 26 | assert_eq!(rgb.r, 4); 27 | assert_eq!(rgb.g, 5); 28 | assert_eq!(rgb.b, 6); 29 | 30 | assert_eq!((3, Some(3)), ::size_hint(0)); 31 | } 32 | 33 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Arbitrary)] 34 | #[allow(non_camel_case_types)] 35 | struct r#struct { 36 | pub r#fn: u8, 37 | pub r#struct: u8, 38 | pub r#let: u8, 39 | } 40 | 41 | #[test] 42 | fn struct_with_raw_named_fields() { 43 | let r#struct: r#struct = arbitrary_from(&[4, 5, 6]); 44 | assert_eq!(r#struct.r#fn, 4); 45 | assert_eq!(r#struct.r#struct, 5); 46 | assert_eq!(r#struct.r#let, 6); 47 | 48 | assert_eq!((3, Some(3)), ::size_hint(0)); 49 | } 50 | 51 | #[derive(Copy, Clone, Debug, Arbitrary)] 52 | struct MyTupleStruct(u8, bool); 53 | 54 | #[test] 55 | fn tuple_struct() { 56 | let s: MyTupleStruct = arbitrary_from(&[43, 42]); 57 | assert_eq!(s.0, 43); 58 | assert_eq!(s.1, false); 59 | 60 | let s: MyTupleStruct = arbitrary_from(&[42, 43]); 61 | assert_eq!(s.0, 42); 62 | assert_eq!(s.1, true); 63 | 64 | assert_eq!((2, Some(2)), ::size_hint(0)); 65 | } 66 | 67 | #[derive(Clone, Debug, Arbitrary)] 68 | struct EndingInVec(u8, bool, u32, Vec); 69 | #[derive(Clone, Debug, Arbitrary)] 70 | struct EndingInString(u8, bool, u32, String); 71 | 72 | #[test] 73 | fn test_take_rest() { 74 | let bytes = [1, 1, 1, 2, 3, 4, 5, 6, 7, 8]; 75 | let s1 = EndingInVec::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap(); 76 | let s2 = EndingInString::arbitrary_take_rest(Unstructured::new(&bytes)).unwrap(); 77 | assert_eq!(s1.0, 1); 78 | assert_eq!(s2.0, 1); 79 | assert_eq!(s1.1, true); 80 | assert_eq!(s2.1, true); 81 | assert_eq!(s1.2, 0x4030201); 82 | assert_eq!(s2.2, 0x4030201); 83 | assert_eq!(s1.3, vec![0x0706]); 84 | assert_eq!(s2.3, "\x05\x06\x07\x08"); 85 | } 86 | 87 | #[derive(Copy, Clone, Debug, Arbitrary)] 88 | enum MyEnum { 89 | Unit, 90 | Tuple(u8, u16), 91 | Struct { a: u32, b: (bool, u64) }, 92 | } 93 | 94 | #[test] 95 | fn derive_enum() { 96 | let mut raw = vec![ 97 | // The choice of which enum variant takes 4 bytes. 98 | 1, 2, 3, 4, 99 | // And then we need up to 13 bytes for creating `MyEnum::Struct`, the 100 | // largest variant. 101 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 102 | ]; 103 | 104 | let mut saw_unit = false; 105 | let mut saw_tuple = false; 106 | let mut saw_struct = false; 107 | 108 | for i in 0..=255 { 109 | // Choose different variants each iteration. 110 | for el in &mut raw[..4] { 111 | *el = i; 112 | } 113 | 114 | let e: MyEnum = arbitrary_from(&raw); 115 | 116 | match e { 117 | MyEnum::Unit => { 118 | saw_unit = true; 119 | } 120 | MyEnum::Tuple(a, b) => { 121 | saw_tuple = true; 122 | assert_eq!(a, arbitrary_from(&raw[4..5])); 123 | assert_eq!(b, arbitrary_from(&raw[5..])); 124 | } 125 | MyEnum::Struct { a, b } => { 126 | saw_struct = true; 127 | assert_eq!(a, arbitrary_from(&raw[4..8])); 128 | assert_eq!(b, arbitrary_from(&raw[8..])); 129 | } 130 | } 131 | } 132 | 133 | assert!(saw_unit); 134 | assert!(saw_tuple); 135 | assert!(saw_struct); 136 | 137 | assert_eq!((4, Some(17)), ::size_hint(0)); 138 | } 139 | 140 | // This should result in a compiler-error: 141 | // #[derive(Arbitrary, Debug)] 142 | // enum Never { 143 | // #[arbitrary(skip)] 144 | // Nope, 145 | // } 146 | 147 | #[derive(Arbitrary, Debug)] 148 | enum SkipVariant { 149 | Always, 150 | #[arbitrary(skip)] 151 | Never, 152 | } 153 | 154 | #[test] 155 | fn test_skip_variant() { 156 | (0..=u8::MAX).for_each(|byte| { 157 | let buffer = [byte]; 158 | let unstructured = Unstructured::new(&buffer); 159 | let skip_variant = SkipVariant::arbitrary_take_rest(unstructured).unwrap(); 160 | assert!(!matches!(skip_variant, SkipVariant::Never)); 161 | }) 162 | } 163 | 164 | #[derive(Arbitrary, Debug)] 165 | enum RecursiveTree { 166 | Leaf, 167 | Node { 168 | left: Box, 169 | right: Box, 170 | }, 171 | } 172 | 173 | #[derive(Arbitrary, Debug)] 174 | struct WideRecursiveStruct { 175 | a: Option>, 176 | b: Option>, 177 | c: Option>, 178 | d: Option>, 179 | e: Option>, 180 | f: Option>, 181 | g: Option>, 182 | h: Option>, 183 | i: Option>, 184 | k: Option>, 185 | } 186 | 187 | #[derive(Arbitrary, Debug)] 188 | enum WideRecursiveEnum { 189 | None, 190 | A(Box), 191 | B(Box), 192 | C(Box), 193 | D(Box), 194 | E(Box), 195 | F(Box), 196 | G(Box), 197 | H(Box), 198 | I(Box), 199 | K(Box), 200 | } 201 | 202 | #[derive(Arbitrary, Debug)] 203 | enum WideRecursiveMixedEnum { 204 | None, 205 | A(Box), 206 | B(Box), 207 | C(Box), 208 | D(Box), 209 | E(Box), 210 | F(Box), 211 | G(Box), 212 | H(Box), 213 | I(Box), 214 | K(Box), 215 | } 216 | 217 | #[derive(Arbitrary, Debug)] 218 | struct WideRecursiveMixedStruct { 219 | a: Option>, 220 | b: Option>, 221 | c: Option>, 222 | d: Option>, 223 | e: Option>, 224 | f: Option>, 225 | g: Option>, 226 | h: Option>, 227 | i: Option>, 228 | k: Option>, 229 | } 230 | 231 | #[test] 232 | fn recursive() { 233 | let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; 234 | let _rec: RecursiveTree = arbitrary_from(&raw); 235 | let _rec: WideRecursiveStruct = arbitrary_from(&raw); 236 | let _rec: WideRecursiveEnum = arbitrary_from(&raw); 237 | let _rec: WideRecursiveMixedStruct = arbitrary_from(&raw); 238 | let _rec: WideRecursiveMixedEnum = arbitrary_from(&raw); 239 | 240 | assert_eq!((0, None), ::size_hint(0)); 241 | assert_eq!((0, None), ::size_hint(0)); 242 | assert_eq!( 243 | (0, None), 244 | ::size_hint(0) 245 | ); 246 | assert_eq!( 247 | (0, None), 248 | ::size_hint(0) 249 | ); 250 | 251 | let (lower, upper) = ::size_hint(0); 252 | assert_eq!(lower, 0, "Cannot compute size hint of recursive structure"); 253 | assert!( 254 | upper.is_none(), 255 | "potentially infinitely recursive, so no upper bound" 256 | ); 257 | } 258 | 259 | #[derive(Arbitrary, Debug)] 260 | struct Generic { 261 | inner: T, 262 | } 263 | 264 | #[test] 265 | fn generics() { 266 | let raw = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; 267 | let gen: Generic = arbitrary_from(&raw); 268 | assert!(gen.inner); 269 | 270 | let (lower, upper) = as Arbitrary>::size_hint(0); 271 | assert_eq!(lower, 4); 272 | assert_eq!(upper, Some(4)); 273 | } 274 | 275 | #[derive(Arbitrary, Debug)] 276 | struct OneLifetime<'a> { 277 | alpha: &'a str, 278 | } 279 | 280 | #[test] 281 | fn one_lifetime() { 282 | // Last byte is used for length 283 | let raw: Vec = vec![97, 98, 99, 100, 3]; 284 | let lifetime: OneLifetime = arbitrary_from(&raw); 285 | assert_eq!("abc", lifetime.alpha); 286 | 287 | let (lower, upper) = ::size_hint(0); 288 | assert_eq!(lower, 0); 289 | assert_eq!(upper, None); 290 | } 291 | 292 | #[derive(Arbitrary, Debug)] 293 | struct TwoLifetimes<'a, 'b> { 294 | alpha: &'a str, 295 | beta: &'b str, 296 | } 297 | 298 | #[test] 299 | fn two_lifetimes() { 300 | // Last byte is used for length 301 | let raw: Vec = vec![97, 98, 99, 100, 101, 102, 103, 3]; 302 | let lifetime: TwoLifetimes = arbitrary_from(&raw); 303 | assert_eq!("abc", lifetime.alpha); 304 | assert_eq!("def", lifetime.beta); 305 | 306 | let (lower, upper) = ::size_hint(0); 307 | assert_eq!(lower, 0); 308 | assert_eq!(upper, None); 309 | } 310 | 311 | #[test] 312 | fn recursive_and_empty_input() { 313 | // None of the following derives should result in a stack overflow. See 314 | // https://github.com/rust-fuzz/arbitrary/issues/107 for details. 315 | 316 | #[derive(Debug, Arbitrary)] 317 | enum Nat { 318 | Succ(Box), 319 | Zero, 320 | } 321 | 322 | let _ = Nat::arbitrary(&mut Unstructured::new(&[])); 323 | 324 | #[derive(Debug, Arbitrary)] 325 | enum Nat2 { 326 | Zero, 327 | Succ(Box), 328 | } 329 | 330 | let _ = Nat2::arbitrary(&mut Unstructured::new(&[])); 331 | 332 | #[derive(Debug, Arbitrary)] 333 | struct Nat3 { 334 | f: Option>, 335 | } 336 | 337 | let _ = Nat3::arbitrary(&mut Unstructured::new(&[])); 338 | 339 | #[derive(Debug, Arbitrary)] 340 | struct Nat4(Option>); 341 | 342 | let _ = Nat4::arbitrary(&mut Unstructured::new(&[])); 343 | 344 | #[derive(Debug, Arbitrary)] 345 | enum Nat5 { 346 | Zero, 347 | Succ { f: Box }, 348 | } 349 | 350 | let _ = Nat5::arbitrary(&mut Unstructured::new(&[])); 351 | } 352 | 353 | #[test] 354 | fn test_field_attributes() { 355 | // A type that DOES NOT implement Arbitrary 356 | #[derive(Debug)] 357 | struct Weight(u8); 358 | 359 | #[derive(Debug, Arbitrary)] 360 | struct Parcel { 361 | #[arbitrary(with = arbitrary_weight)] 362 | weight: Weight, 363 | 364 | #[arbitrary(default)] 365 | width: u8, 366 | 367 | #[arbitrary(value = 2 + 2)] 368 | length: u8, 369 | 370 | height: u8, 371 | 372 | #[arbitrary(with = |u: &mut Unstructured| u.int_in_range(0..=100))] 373 | price: u8, 374 | } 375 | 376 | fn arbitrary_weight(u: &mut Unstructured) -> arbitrary::Result { 377 | u.int_in_range(45..=56).map(Weight) 378 | } 379 | 380 | let parcel: Parcel = arbitrary_from(&[6, 199, 17]); 381 | 382 | // 45 + 6 = 51 383 | assert_eq!(parcel.weight.0, 51); 384 | 385 | // u8::default() 386 | assert_eq!(parcel.width, 0); 387 | 388 | // 2 + 2 = 4 389 | assert_eq!(parcel.length, 4); 390 | 391 | // 199 is the 2nd byte used by arbitrary 392 | assert_eq!(parcel.height, 199); 393 | 394 | // 17 is the 3rd byte used by arbitrary 395 | assert_eq!(parcel.price, 17); 396 | } 397 | 398 | #[test] 399 | fn derive_structs_named_same_as_core() { 400 | #[derive(Debug, Arbitrary)] 401 | struct Option { 402 | f: core::option::Option, 403 | } 404 | 405 | let _ = Option::arbitrary(&mut Unstructured::new(&[])); 406 | 407 | #[derive(Debug, Default, Arbitrary)] 408 | struct Default { 409 | f: u32, 410 | } 411 | 412 | let _ = Default::arbitrary(&mut Unstructured::new(&[])); 413 | 414 | #[derive(Debug, Arbitrary)] 415 | struct Result { 416 | f: core::result::Result, 417 | } 418 | 419 | let _ = Result::arbitrary(&mut Unstructured::new(&[])); 420 | } 421 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Unreleased 2 | 3 | Released YYYY-MM-DD. 4 | 5 | ### Added 6 | 7 | * TODO (or remove section if none) 8 | 9 | ### Changed 10 | 11 | * TODO (or remove section if none) 12 | 13 | ### Deprecated 14 | 15 | * TODO (or remove section if none) 16 | 17 | ### Removed 18 | 19 | * TODO (or remove section if none) 20 | 21 | ### Fixed 22 | 23 | * TODO (or remove section if none) 24 | 25 | ### Security 26 | 27 | * TODO (or remove section if none) 28 | 29 | -------------------------------------------------------------------------------- 30 | 31 | ## 1.4.2 32 | 33 | Released 2025-08-13. 34 | 35 | ### Added 36 | 37 | * Added formal MSRV policy: "We reserve the right to increment the MSRV on minor 38 | releases, however we will strive to only do it deliberately and for good 39 | reasons." The current MSRV is 1.63.0. 40 | * Added an `Arbitrary` implementation for `core::cmp::Reverse`. 41 | 42 | ### Changed 43 | 44 | * Landed a handful of changes to the code generated by `#[derive(Arbitrary)]` 45 | that speed up compilation. 46 | 47 | ### Fixed 48 | 49 | * Better documented bias and behavior when running out of entropy, fixed some 50 | outdated and incorrect docs related to this. 51 | 52 | -------------------------------------------------------------------------------- 53 | 54 | ## 1.4.1 55 | 56 | Released 2024-11-05. 57 | 58 | -------------------------------------------------------------------------------- 59 | 60 | ## 1.4.0 61 | 62 | Released 2024-10-30. 63 | 64 | ### Added 65 | 66 | * Added an `Arbitrary` implementation for `PhantomPinned`. 67 | * Added the `Unstructured::choose_iter` helper method. 68 | * Added `#[arbitrary(skip)]` for `enum` variants in the derive macro. 69 | * Added the `Arbitrary::try_size_hint` trait method. 70 | 71 | ### Changed 72 | 73 | * Implement `Arbitrary` for `PhantomData` even when `A` does not implement 74 | `Arbitrary` and when `A` is `?Sized`. 75 | * Make `usize`'s underlying encoding independent of machine word size so that 76 | corpora are more portable. 77 | 78 | ### Fixed 79 | 80 | * Make `derive(Arbitrary)` work for local definitions of `struct Option`. 81 | 82 | -------------------------------------------------------------------------------- 83 | 84 | ## 1.3.2 85 | 86 | Released 2023-10-30. 87 | 88 | ### Added 89 | 90 | * Added `Arbitrary` implementations for `Arc<[T]>` and 91 | `Rc<[T]>`. [#160](https://github.com/rust-fuzz/arbitrary/pull/160) 92 | 93 | -------------------------------------------------------------------------------- 94 | 95 | ## 1.3.1 96 | 97 | Released 2023-10-11. 98 | 99 | ### Fixed 100 | 101 | * Fixed an issue with generating collections of collections in 102 | `arbitrary_take_rest` where `>>::arbitrary_take_rest` would never 103 | generate `vec![vec![]]` for example. See 104 | [#159](https://github.com/rust-fuzz/arbitrary/pull/159) for details. 105 | 106 | -------------------------------------------------------------------------------- 107 | 108 | ## 1.3.0 109 | 110 | Released 2023-03-13. 111 | 112 | ### Added 113 | 114 | * Added the ability to manually specify derived trait bounds for 115 | `Arbitrary`. See [#138](https://github.com/rust-fuzz/arbitrary/pull/138) for 116 | details. 117 | 118 | ### Fixed 119 | 120 | * Fixed minimal versions correctness for `syn`. 121 | 122 | -------------------------------------------------------------------------------- 123 | 124 | ## 1.2.3 125 | 126 | Released 2023-01-20. 127 | 128 | ### Fixed 129 | 130 | * The `derive(Arbitrary)` will now annotate the generated `impl`s with a `#[automatically_derived]` 131 | attribute to indicate to e.g. clippy that lints should not fire for the code within the derived 132 | implementation. 133 | 134 | ## 1.2.2 135 | 136 | Released 2023-01-03. 137 | 138 | ### Fixed 139 | 140 | * Ensured that `arbitrary` and `derive_arbitrary` versions are synced up so that 141 | they don't, e.g., emit generated code that depends on newer versions of 142 | `arbitrary` than the one currently in 143 | use. [#134](https://github.com/rust-fuzz/arbitrary/issues/134) 144 | 145 | ## 1.2.1 146 | 147 | ### Fixed 148 | 149 | * Fixed an issue where `std::thread_local!` macro invocations in derive code 150 | were not fully prefixed, causing confusing build errors in certain situations. 151 | 152 | ## 1.2.0 153 | 154 | Released 2022-10-20. 155 | 156 | ### Added 157 | 158 | * Support custom arbitrary implementation for fields on 159 | derive. [#129](https://github.com/rust-fuzz/arbitrary/pull/129) 160 | 161 | -------------------------------------------------------------------------------- 162 | 163 | ## 1.1.6 164 | 165 | Released 2022-09-20. 166 | 167 | ### Fixed 168 | 169 | * Fixed a potential panic due to an off-by-one error in the `Arbitrary` 170 | implementation for `std::ops::Bound`. 171 | 172 | -------------------------------------------------------------------------------- 173 | 174 | ## 1.1.5 175 | 176 | Released 2022-09-08. 177 | 178 | ### Added 179 | 180 | * Implemented `Arbitrary` for `std::ops::Bound`. 181 | 182 | ### Fixed 183 | 184 | * Fixed a bug where `Unstructured::int_in_range` could return out-of-range 185 | integers when generating arbitrary signed integers. 186 | 187 | -------------------------------------------------------------------------------- 188 | 189 | ## 1.1.4 190 | 191 | Released 2022-08-29. 192 | 193 | ### Added 194 | 195 | * Implemented `Arbitrary` for `Rc` and `Arc` 196 | 197 | ### Changed 198 | 199 | * Allow overriding the error type in `arbitrary::Result` 200 | * The `Unstructured::arbitrary_loop` method will consume fewer bytes of input 201 | now. 202 | 203 | ### Fixed 204 | 205 | * Fixed a bug where `Unstructured::int_in_range` could return out-of-range 206 | integers. 207 | 208 | -------------------------------------------------------------------------------- 209 | 210 | ## 1.1.3 211 | 212 | Released 2022-06-23. 213 | 214 | ### Fixed 215 | 216 | * Fixed some potential (but highly unlikely) name-clashes inside 217 | `derive(Arbitrary)`'s generated 218 | code. [#111](https://github.com/rust-fuzz/arbitrary/pull/111) 219 | * Fixed an edge case where `derive(Arbitrary)` for recursive types that detected 220 | an overflow would not reset the overflow 221 | detection. [#111](https://github.com/rust-fuzz/arbitrary/pull/111) 222 | 223 | -------------------------------------------------------------------------------- 224 | 225 | ## 1.1.2 226 | 227 | Released 2022-06-16. 228 | 229 | ### Fixed 230 | 231 | * Fixed a warning inside `derive(Arbitrary)`-generated 232 | code. [#110](https://github.com/rust-fuzz/arbitrary/pull/110) 233 | 234 | -------------------------------------------------------------------------------- 235 | 236 | ## 1.1.1 237 | 238 | Released 2022-06-14. 239 | 240 | ### Fixed 241 | 242 | * Fixed a stack overflow when using `derive(Arbitrary)` with recursive types and 243 | empty inputs. [#109](https://github.com/rust-fuzz/arbitrary/pull/109) 244 | 245 | -------------------------------------------------------------------------------- 246 | 247 | ## 1.1.0 248 | 249 | Released 2022-02-09. 250 | 251 | ### Added 252 | 253 | * Added the `Unstructured::ratio` method to generate a boolean that is `true` at 254 | the given rate. 255 | 256 | * Added the `Unstructured::arbitrary_loop` method to call a function an 257 | arbitrary number of times. 258 | 259 | -------------------------------------------------------------------------------- 260 | 261 | ## 1.0.3 262 | 263 | Released 2021-11-20. 264 | 265 | ### Fixed 266 | 267 | * Fixed documentation for `Unstructured::fill_bytes`. We forgot to update this 268 | way back in [#53](https://github.com/rust-fuzz/arbitrary/pull/53) when the 269 | behavior changed. 270 | 271 | -------------------------------------------------------------------------------- 272 | 273 | ## 1.0.2 274 | 275 | Released 2021-08-25. 276 | 277 | ### Added 278 | 279 | * `Arbitrary` impls for `HashMap`s and `HashSet`s with custom `Hasher`s 280 | [#87](https://github.com/rust-fuzz/arbitrary/pull/87) 281 | 282 | -------------------------------------------------------------------------------- 283 | 284 | ## 1.0.1 285 | 286 | Released 2021-05-20. 287 | 288 | ### Added 289 | 290 | * `Arbitrary` impls for `NonZeroX` types [#79](https://github.com/rust-fuzz/arbitrary/pull/79) 291 | * `Arbitrary` impls for all arrays using const generics [#55](https://github.com/rust-fuzz/arbitrary/pull/55) 292 | * `Arbitrary` impls for `Ipv4Addr` and `Ipv6Addr` [#84](https://github.com/rust-fuzz/arbitrary/pull/84) 293 | 294 | ### Fixed 295 | 296 | * Use fewer bytes for `Unstructured::int_in_range()` [#80](https://github.com/rust-fuzz/arbitrary/pull/80) 297 | * Use correct range for `char` generation [#83](https://github.com/rust-fuzz/arbitrary/pull/83) 298 | 299 | -------------------------------------------------------------------------------- 300 | 301 | ## 1.0.0 302 | 303 | Released 2020-02-24. 304 | 305 | See 1.0.0-rc1 and 1.0.0-rc2 for changes since 0.4.7, which was the last main 306 | line release. 307 | 308 | -------------------------------------------------------------------------------- 309 | 310 | ## 1.0.0-rc2 311 | 312 | Released 2021-02-09. 313 | 314 | ### Added 315 | 316 | * The `Arbitrary` trait is now implemented for `&[u8]`. [#67](https://github.com/rust-fuzz/arbitrary/pull/67) 317 | 318 | ### Changed 319 | 320 | * Rename `Unstructured#get_bytes` to `Unstructured#bytes`. [#70](https://github.com/rust-fuzz/arbitrary/pull/70) 321 | * Passing an empty slice of choices to `Unstructured#choose` returns an error. Previously it would panic. [71](https://github.com/rust-fuzz/arbitrary/pull/71) 322 | 323 | -------------------------------------------------------------------------------- 324 | 325 | ## 1.0.0-rc1 326 | 327 | Released 2020-11-25. 328 | 329 | ### Added 330 | 331 | * The `Arbitrary` trait is now implemented for `&str`. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) 332 | 333 | ### Changed 334 | 335 | * The `Arbitrary` trait now has a lifetime parameter, allowing `Arbitrary` implementations that borrow from the raw input (e.g. the new `&str` implementaton). The `derive(Arbitrary)` macro also supports deriving `Arbitrary` on types with lifetimes now. [#63](https://github.com/rust-fuzz/arbitrary/pull/63) 336 | 337 | ### Removed 338 | 339 | * The `shrink` method on the `Arbitrary` trait has been removed. 340 | 341 | We have found that, in practice, using [internal reduction](https://drmaciver.github.io/papers/reduction-via-generation-preview.pdf) via approaches like `cargo fuzz tmin`, where the raw input bytes are reduced rather than the `T: Arbitrary` type constructed from those raw bytes, has the best efficiency-to-maintenance ratio. To the best of our knowledge, no one is relying on or using the `Arbitrary::shrink` method. If you *are* using and relying on the `Arbitrary::shrink` method, please reach out by [dropping a comment here](https://github.com/rust-fuzz/arbitrary/issues/62) and explaining how you're using it and what your use case is. We'll figure out what the best solution is, including potentially adding shrinking functionality back to the `arbitrary` crate. 342 | 343 | -------------------------------------------------------------------------------- 344 | 345 | ## 0.4.7 346 | 347 | Released 2020-10-14. 348 | 349 | ### Added 350 | 351 | * Added an optimization to avoid unnecessarily consuming bytes from the 352 | underlying data when there is only one possible choice in 353 | `Unstructured::{int_in_range, choose, etc..}`. 354 | 355 | * Added license files to the derive crate. 356 | 357 | ### Changed 358 | 359 | * The `Arbitrary` implementation for `std::time::Duration` should now be faster 360 | and produce durations with a more-uniform distribution of nanoseconds. 361 | 362 | -------------------------------------------------------------------------------- 363 | 364 | ## 0.4.6 365 | 366 | Released 2020-08-22. 367 | 368 | ### Added 369 | 370 | * Added the `Unstructured::peek_bytes` method. 371 | 372 | ### Changed 373 | 374 | * Test case reduction via `cargo fuzz tmin` should be much more effective at 375 | reducing the sizes of collections now. (See 376 | [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit messages 377 | for details.) 378 | 379 | * Fuzzing with mutation-based fuzzers (like libFuzzer) should be more efficient 380 | now. (See [#53](https://github.com/rust-fuzz/arbitrary/pull/53) and the commit 381 | messages for details) 382 | 383 | -------------------------------------------------------------------------------- 384 | 385 | ## 0.4.5 386 | 387 | Released 2020-06-18. 388 | 389 | ### Added 390 | 391 | * Implement `Arbitrary` for zero length arrays. 392 | * Implement `Arbitrary` for `Range` and `RangeInclusive`. 393 | 394 | -------------------------------------------------------------------------------- 395 | 396 | ## 0.4.4 397 | 398 | Released 2020-04-29. 399 | 400 | ### Fixed 401 | 402 | * Fixed the custom derive for enums when used via its full path (like 403 | `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`). 404 | 405 | 406 | ## 0.4.3 407 | 408 | Released 2020-04-28. 409 | 410 | ### Fixed 411 | 412 | * Fixed the custom derive when used via its full path (like 413 | `#[derive(arbitrary::Arbitrary)]` rather than like `#[derive(Arbitrary)]`). 414 | 415 | -------------------------------------------------------------------------------- 416 | 417 | ## 0.4.2 418 | 419 | Released 2020-04-17. 420 | 421 | ### Changed 422 | 423 | * We forgot to release a new version of the `derive_arbitrary` crate last 424 | release. This release fixes that and so the `synstructure` dependency is 425 | finally actually removed in the cargo releases. 426 | 427 | -------------------------------------------------------------------------------- 428 | 429 | ## 0.4.1 430 | 431 | Released 2020-03-18. 432 | 433 | ### Removed 434 | 435 | * Removed an internal dependency on the `synstructure` crate when the `derive` 436 | feature is enabled. This should not have any visible downstream effects other 437 | than faster build times! 438 | 439 | -------------------------------------------------------------------------------- 440 | 441 | ## 0.4.0 442 | 443 | Released 2020-01-22. 444 | 445 | This is technically a breaking change, but we expect that nearly everyone should 446 | be able to upgrade without any compilation errors. The only exception is if you 447 | were implementing the `Arbitrary::size_hint` method by hand. If so, see the 448 | "changed" section below and the [API docs for 449 | `Arbitrary::shrink`](https://docs.rs/arbitrary/0.4.0/arbitrary/trait.Arbitrary.html#method.size_hint) 450 | for details. 451 | 452 | ### Added 453 | 454 | * Added [the `arbitary::size_hint::recursion_guard` helper 455 | function][recursion_guard] for guarding against infinite recursion in 456 | `size_hint` implementations for recursive types. 457 | 458 | ### Changed 459 | 460 | * The `Arbitrary::size_hint` signature now takes a `depth: usize` 461 | parameter. This should be passed along unmodified to any nested calls of other 462 | `size_hint` methods. If you're implementing `size_hint` for a recursive type 463 | (like a linked list or tree) or a generic type with type parameters, you 464 | should use [the new `arbitrary::size_hint::recursion_guard` helper 465 | function][recursion_guard]. 466 | 467 | ### Fixed 468 | 469 | * Fixed infinite recursion in generated `size_hint` implementations 470 | from `#[derive(Arbitrary)]` for recursive types. 471 | 472 | [recursion_guard]: https://docs.rs/arbitrary/0.4.0/arbitrary/size_hint/fn.recursion_guard.html 473 | 474 | -------------------------------------------------------------------------------- 475 | 476 | ## 0.3.2 477 | 478 | Released 2020-01-16. 479 | 480 | ### Changed 481 | 482 | * Updated the custom derive's dependencies. 483 | 484 | -------------------------------------------------------------------------------- 485 | 486 | ## 0.3.2 487 | 488 | Released 2020-01-15. 489 | 490 | ### Fixed 491 | 492 | * Fixed an over-eager assertion condition in `Unstructured::int_in_range` that 493 | would incorrectly trigger when given valid ranges of length one. 494 | 495 | -------------------------------------------------------------------------------- 496 | 497 | ## 0.3.1 498 | 499 | Released 2020-01-14. 500 | 501 | ### Fixed 502 | 503 | * Fixed some links and version numbers in README. 504 | 505 | -------------------------------------------------------------------------------- 506 | 507 | ## 0.3.0 508 | 509 | Released 2020-01-14. 510 | 511 | ### Added 512 | 513 | * Added the `"derive"` cargo feature, to enable `#[derive(Arbitrary)]` for 514 | custom types. Enabling this feature re-exports functionality from the 515 | `derive_arbitrary` crate. 516 | * The custom derive for `Arbitrary` implements the shrink method for you now. 517 | * All implementations of `Arbitrary` for `std` types implement shrinking now. 518 | * Added the `Arbitrary::arbitrary_take_rest` method allows an `Arbitrary` 519 | implementation to consume all of the rest of the remaining raw input. It has a 520 | default implementation that forwards to `Arbitrary::arbitrary` and the custom 521 | derive creates a smart implementation for your custom types. 522 | * Added the `Arbitrary::size_hint` method for hinting how many raw bytes an 523 | implementation needs to construct itself. This has a default implementation, 524 | but the custom derive creates a smart implementation for your custom types. 525 | * Added the `Unstructured::choose` method to choose one thing among a set of 526 | choices. 527 | * Added the `Unstructured::arbitrary_len` method to get an arbitrary length for 528 | a collection of some arbitrary type. 529 | * Added the `Unstructured::arbitrary_iter` method to create an iterator of 530 | arbitrary instance of some type. 531 | 532 | ### Changed 533 | 534 | * The `Arbitrary` trait was simplified a bit. 535 | * `Unstructured` is a concrete type now, not a trait. 536 | * Switched to Rust 2018 edition. 537 | 538 | ### Removed 539 | 540 | * `RingBuffer` and `FiniteBuffer` are removed. Use `Unstructured` instead. 541 | 542 | ### Fixed 543 | 544 | * Better `Arbitrary` implementation for `char`. 545 | * Better `Arbitrary` implementation for `String`. 546 | 547 | -------------------------------------------------------------------------------- 548 | 549 | ## 0.2.0 550 | 551 | -------------------------------------------------------------------------------- 552 | 553 | ## 0.1.0 554 | -------------------------------------------------------------------------------- /derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | 3 | use proc_macro2::{Span, TokenStream}; 4 | use quote::quote; 5 | use syn::{ext::IdentExt as _, *}; 6 | 7 | mod container_attributes; 8 | mod field_attributes; 9 | mod variant_attributes; 10 | 11 | use container_attributes::ContainerAttributes; 12 | use field_attributes::{determine_field_constructor, FieldConstructor}; 13 | use variant_attributes::not_skipped; 14 | 15 | const ARBITRARY_ATTRIBUTE_NAME: &str = "arbitrary"; 16 | const ARBITRARY_LIFETIME_NAME: &str = "'arbitrary"; 17 | 18 | #[proc_macro_derive(Arbitrary, attributes(arbitrary))] 19 | pub fn derive_arbitrary(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { 20 | let input = syn::parse_macro_input!(tokens as syn::DeriveInput); 21 | expand_derive_arbitrary(input) 22 | .unwrap_or_else(syn::Error::into_compile_error) 23 | .into() 24 | } 25 | 26 | fn expand_derive_arbitrary(input: syn::DeriveInput) -> Result { 27 | let container_attrs = ContainerAttributes::from_derive_input(&input)?; 28 | 29 | let (lifetime_without_bounds, lifetime_with_bounds) = 30 | build_arbitrary_lifetime(input.generics.clone()); 31 | 32 | // This won't be used if `needs_recursive_count` ends up false. 33 | let recursive_count = syn::Ident::new( 34 | &format!("RECURSIVE_COUNT_{}", input.ident.unraw()), 35 | Span::call_site(), 36 | ); 37 | 38 | let (arbitrary_method, needs_recursive_count) = 39 | gen_arbitrary_method(&input, lifetime_without_bounds.clone(), &recursive_count)?; 40 | let size_hint_method = gen_size_hint_method(&input, needs_recursive_count)?; 41 | let name = input.ident; 42 | 43 | // Apply user-supplied bounds or automatic `T: ArbitraryBounds`. 44 | let generics = apply_trait_bounds( 45 | input.generics, 46 | lifetime_without_bounds.clone(), 47 | &container_attrs, 48 | )?; 49 | 50 | // Build ImplGeneric with a lifetime (https://github.com/dtolnay/syn/issues/90) 51 | let mut generics_with_lifetime = generics.clone(); 52 | generics_with_lifetime 53 | .params 54 | .push(GenericParam::Lifetime(lifetime_with_bounds)); 55 | let (impl_generics, _, _) = generics_with_lifetime.split_for_impl(); 56 | 57 | // Build TypeGenerics and WhereClause without a lifetime 58 | let (_, ty_generics, where_clause) = generics.split_for_impl(); 59 | 60 | let recursive_count = needs_recursive_count.then(|| { 61 | Some(quote! { 62 | ::std::thread_local! { 63 | #[allow(non_upper_case_globals)] 64 | static #recursive_count: ::core::cell::Cell = const { 65 | ::core::cell::Cell::new(0) 66 | }; 67 | } 68 | }) 69 | }); 70 | 71 | Ok(quote! { 72 | const _: () = { 73 | #recursive_count 74 | 75 | #[automatically_derived] 76 | impl #impl_generics arbitrary::Arbitrary<#lifetime_without_bounds> 77 | for #name #ty_generics #where_clause 78 | { 79 | #arbitrary_method 80 | #size_hint_method 81 | } 82 | }; 83 | }) 84 | } 85 | 86 | // Returns: (lifetime without bounds, lifetime with bounds) 87 | // Example: ("'arbitrary", "'arbitrary: 'a + 'b") 88 | fn build_arbitrary_lifetime(generics: Generics) -> (LifetimeParam, LifetimeParam) { 89 | let lifetime_without_bounds = 90 | LifetimeParam::new(Lifetime::new(ARBITRARY_LIFETIME_NAME, Span::call_site())); 91 | let mut lifetime_with_bounds = lifetime_without_bounds.clone(); 92 | 93 | for param in generics.params.iter() { 94 | if let GenericParam::Lifetime(lifetime_def) = param { 95 | lifetime_with_bounds 96 | .bounds 97 | .push(lifetime_def.lifetime.clone()); 98 | } 99 | } 100 | 101 | (lifetime_without_bounds, lifetime_with_bounds) 102 | } 103 | 104 | fn apply_trait_bounds( 105 | mut generics: Generics, 106 | lifetime: LifetimeParam, 107 | container_attrs: &ContainerAttributes, 108 | ) -> Result { 109 | // If user-supplied bounds exist, apply them to their matching type parameters. 110 | if let Some(config_bounds) = &container_attrs.bounds { 111 | let mut config_bounds_applied = 0; 112 | for param in generics.params.iter_mut() { 113 | if let GenericParam::Type(type_param) = param { 114 | if let Some(replacement) = config_bounds 115 | .iter() 116 | .flatten() 117 | .find(|p| p.ident == type_param.ident) 118 | { 119 | *type_param = replacement.clone(); 120 | config_bounds_applied += 1; 121 | } else { 122 | // If no user-supplied bounds exist for this type, delete the original bounds. 123 | // This mimics serde. 124 | type_param.bounds = Default::default(); 125 | type_param.default = None; 126 | } 127 | } 128 | } 129 | let config_bounds_supplied = config_bounds 130 | .iter() 131 | .map(|bounds| bounds.len()) 132 | .sum::(); 133 | if config_bounds_applied != config_bounds_supplied { 134 | return Err(Error::new( 135 | Span::call_site(), 136 | format!( 137 | "invalid `{}` attribute. too many bounds, only {} out of {} are applicable", 138 | ARBITRARY_ATTRIBUTE_NAME, config_bounds_applied, config_bounds_supplied, 139 | ), 140 | )); 141 | } 142 | Ok(generics) 143 | } else { 144 | // Otherwise, inject a `T: Arbitrary` bound for every parameter. 145 | Ok(add_trait_bounds(generics, lifetime)) 146 | } 147 | } 148 | 149 | // Add a bound `T: Arbitrary` to every type parameter T. 150 | fn add_trait_bounds(mut generics: Generics, lifetime: LifetimeParam) -> Generics { 151 | for param in generics.params.iter_mut() { 152 | if let GenericParam::Type(type_param) = param { 153 | type_param 154 | .bounds 155 | .push(parse_quote!(arbitrary::Arbitrary<#lifetime>)); 156 | } 157 | } 158 | generics 159 | } 160 | 161 | fn gen_arbitrary_method( 162 | input: &DeriveInput, 163 | lifetime: LifetimeParam, 164 | recursive_count: &syn::Ident, 165 | ) -> Result<(TokenStream, bool)> { 166 | fn arbitrary_structlike( 167 | fields: &Fields, 168 | ident: &syn::Ident, 169 | lifetime: LifetimeParam, 170 | recursive_count: &syn::Ident, 171 | ) -> Result { 172 | let arbitrary = construct(fields, |_idx, field| gen_constructor_for_field(field))?; 173 | let body = quote! { 174 | arbitrary::details::with_recursive_count(u, &#recursive_count, |mut u| { 175 | Ok(#ident #arbitrary) 176 | }) 177 | }; 178 | 179 | let arbitrary_take_rest = construct_take_rest(fields)?; 180 | let take_rest_body = quote! { 181 | arbitrary::details::with_recursive_count(u, &#recursive_count, |mut u| { 182 | Ok(#ident #arbitrary_take_rest) 183 | }) 184 | }; 185 | 186 | Ok(quote! { 187 | fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { 188 | #body 189 | } 190 | 191 | fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) -> arbitrary::Result { 192 | #take_rest_body 193 | } 194 | }) 195 | } 196 | 197 | fn arbitrary_variant( 198 | index: u64, 199 | enum_name: &Ident, 200 | variant_name: &Ident, 201 | ctor: TokenStream, 202 | ) -> TokenStream { 203 | quote! { #index => #enum_name::#variant_name #ctor } 204 | } 205 | 206 | fn arbitrary_enum_method( 207 | recursive_count: &syn::Ident, 208 | unstructured: TokenStream, 209 | variants: &[TokenStream], 210 | needs_recursive_count: bool, 211 | ) -> TokenStream { 212 | let count = variants.len() as u64; 213 | 214 | let do_variants = quote! { 215 | // Use a multiply + shift to generate a ranged random number 216 | // with slight bias. For details, see: 217 | // https://lemire.me/blog/2016/06/30/fast-random-shuffling 218 | Ok(match ( 219 | u64::from(::arbitrary(#unstructured)?) * #count 220 | ) >> 32 221 | { 222 | #(#variants,)* 223 | _ => unreachable!() 224 | }) 225 | }; 226 | 227 | if needs_recursive_count { 228 | quote! { 229 | arbitrary::details::with_recursive_count(u, &#recursive_count, |mut u| { 230 | #do_variants 231 | }) 232 | } 233 | } else { 234 | do_variants 235 | } 236 | } 237 | 238 | fn arbitrary_enum( 239 | DataEnum { variants, .. }: &DataEnum, 240 | enum_name: &Ident, 241 | lifetime: LifetimeParam, 242 | recursive_count: &syn::Ident, 243 | ) -> Result<(TokenStream, bool)> { 244 | let filtered_variants = variants.iter().filter(not_skipped); 245 | 246 | // Check attributes of all variants: 247 | filtered_variants 248 | .clone() 249 | .try_for_each(check_variant_attrs)?; 250 | 251 | // From here on, we can assume that the attributes of all variants were checked. 252 | let enumerated_variants = filtered_variants 253 | .enumerate() 254 | .map(|(index, variant)| (index as u64, variant)); 255 | 256 | // Construct `match`-arms for the `arbitrary` method. 257 | let mut needs_recursive_count = false; 258 | let variants = enumerated_variants 259 | .clone() 260 | .map(|(index, Variant { fields, ident, .. })| { 261 | construct(fields, |_, field| gen_constructor_for_field(field)).map(|ctor| { 262 | if !ctor.is_empty() { 263 | needs_recursive_count = true; 264 | } 265 | arbitrary_variant(index, enum_name, ident, ctor) 266 | }) 267 | }) 268 | .collect::>>()?; 269 | 270 | // Construct `match`-arms for the `arbitrary_take_rest` method. 271 | let variants_take_rest = enumerated_variants 272 | .map(|(index, Variant { fields, ident, .. })| { 273 | construct_take_rest(fields) 274 | .map(|ctor| arbitrary_variant(index, enum_name, ident, ctor)) 275 | }) 276 | .collect::>>()?; 277 | 278 | // Most of the time, `variants` is not empty (the happy path), 279 | // thus `variants_take_rest` will be used, 280 | // so no need to move this check before constructing `variants_take_rest`. 281 | // If `variants` is empty, this will emit a compiler-error. 282 | (!variants.is_empty()) 283 | .then(|| { 284 | // TODO: Improve dealing with `u` vs. `&mut u`. 285 | let arbitrary = arbitrary_enum_method( 286 | recursive_count, 287 | quote! { u }, 288 | &variants, 289 | needs_recursive_count, 290 | ); 291 | let arbitrary_take_rest = arbitrary_enum_method( 292 | recursive_count, 293 | quote! { &mut u }, 294 | &variants_take_rest, 295 | needs_recursive_count, 296 | ); 297 | 298 | ( 299 | quote! { 300 | fn arbitrary(u: &mut arbitrary::Unstructured<#lifetime>) 301 | -> arbitrary::Result 302 | { 303 | #arbitrary 304 | } 305 | 306 | fn arbitrary_take_rest(mut u: arbitrary::Unstructured<#lifetime>) 307 | -> arbitrary::Result 308 | { 309 | #arbitrary_take_rest 310 | } 311 | }, 312 | needs_recursive_count, 313 | ) 314 | }) 315 | .ok_or_else(|| { 316 | Error::new_spanned( 317 | enum_name, 318 | "Enum must have at least one variant, that is not skipped", 319 | ) 320 | }) 321 | } 322 | 323 | let ident = &input.ident; 324 | let needs_recursive_count = true; 325 | match &input.data { 326 | Data::Struct(data) => arbitrary_structlike(&data.fields, ident, lifetime, recursive_count) 327 | .map(|ts| (ts, needs_recursive_count)), 328 | Data::Union(data) => arbitrary_structlike( 329 | &Fields::Named(data.fields.clone()), 330 | ident, 331 | lifetime, 332 | recursive_count, 333 | ) 334 | .map(|ts| (ts, needs_recursive_count)), 335 | Data::Enum(data) => arbitrary_enum(data, ident, lifetime, recursive_count), 336 | } 337 | } 338 | 339 | fn construct( 340 | fields: &Fields, 341 | ctor: impl Fn(usize, &Field) -> Result, 342 | ) -> Result { 343 | let output = match fields { 344 | Fields::Named(names) => { 345 | let names: Vec = names 346 | .named 347 | .iter() 348 | .enumerate() 349 | .map(|(i, f)| { 350 | let name = f.ident.as_ref().unwrap(); 351 | ctor(i, f).map(|ctor| quote! { #name: #ctor }) 352 | }) 353 | .collect::>()?; 354 | quote! { { #(#names,)* } } 355 | } 356 | Fields::Unnamed(names) => { 357 | let names: Vec = names 358 | .unnamed 359 | .iter() 360 | .enumerate() 361 | .map(|(i, f)| ctor(i, f).map(|ctor| quote! { #ctor })) 362 | .collect::>()?; 363 | quote! { ( #(#names),* ) } 364 | } 365 | Fields::Unit => quote!(), 366 | }; 367 | Ok(output) 368 | } 369 | 370 | fn construct_take_rest(fields: &Fields) -> Result { 371 | construct(fields, |idx, field| { 372 | determine_field_constructor(field).map(|field_constructor| match field_constructor { 373 | FieldConstructor::Default => quote!(::core::default::Default::default()), 374 | FieldConstructor::Arbitrary => { 375 | if idx + 1 == fields.len() { 376 | quote! { arbitrary::Arbitrary::arbitrary_take_rest(u)? } 377 | } else { 378 | quote! { arbitrary::Arbitrary::arbitrary(&mut u)? } 379 | } 380 | } 381 | FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(&mut u)?), 382 | FieldConstructor::Value(value) => quote!(#value), 383 | }) 384 | }) 385 | } 386 | 387 | fn gen_size_hint_method(input: &DeriveInput, needs_recursive_count: bool) -> Result { 388 | let size_hint_fields = |fields: &Fields| { 389 | fields 390 | .iter() 391 | .map(|f| { 392 | let ty = &f.ty; 393 | determine_field_constructor(f).map(|field_constructor| { 394 | match field_constructor { 395 | FieldConstructor::Default | FieldConstructor::Value(_) => { 396 | quote!(Ok((0, Some(0)))) 397 | } 398 | FieldConstructor::Arbitrary => { 399 | quote! { <#ty as arbitrary::Arbitrary>::try_size_hint(depth) } 400 | } 401 | 402 | // Note that in this case it's hard to determine what size_hint must be, so 403 | // size_of::() is just an educated guess, although it's gonna be 404 | // inaccurate for dynamically allocated types (Vec, HashMap, etc.). 405 | FieldConstructor::With(_) => { 406 | quote! { Ok((::core::mem::size_of::<#ty>(), None)) } 407 | } 408 | } 409 | }) 410 | }) 411 | .collect::>>() 412 | .map(|hints| { 413 | quote! { 414 | Ok(arbitrary::size_hint::and_all(&[ 415 | #( #hints? ),* 416 | ])) 417 | } 418 | }) 419 | }; 420 | let size_hint_structlike = |fields: &Fields| { 421 | assert!(needs_recursive_count); 422 | size_hint_fields(fields).map(|hint| { 423 | quote! { 424 | #[inline] 425 | fn size_hint(depth: usize) -> (usize, ::core::option::Option) { 426 | Self::try_size_hint(depth).unwrap_or_default() 427 | } 428 | 429 | #[inline] 430 | fn try_size_hint(depth: usize) 431 | -> ::core::result::Result< 432 | (usize, ::core::option::Option), 433 | arbitrary::MaxRecursionReached, 434 | > 435 | { 436 | arbitrary::size_hint::try_recursion_guard(depth, |depth| #hint) 437 | } 438 | } 439 | }) 440 | }; 441 | match &input.data { 442 | Data::Struct(data) => size_hint_structlike(&data.fields), 443 | Data::Union(data) => size_hint_structlike(&Fields::Named(data.fields.clone())), 444 | Data::Enum(data) => data 445 | .variants 446 | .iter() 447 | .filter(not_skipped) 448 | .map(|Variant { fields, .. }| { 449 | if !needs_recursive_count { 450 | assert!(fields.is_empty()); 451 | } 452 | // The attributes of all variants are checked in `gen_arbitrary_method` above 453 | // and can therefore assume that they are valid. 454 | size_hint_fields(fields) 455 | }) 456 | .collect::>>() 457 | .map(|variants| { 458 | if needs_recursive_count { 459 | // The enum might be recursive: `try_size_hint` is the primary one, and 460 | // `size_hint` is defined in terms of it. 461 | quote! { 462 | fn size_hint(depth: usize) -> (usize, ::core::option::Option) { 463 | Self::try_size_hint(depth).unwrap_or_default() 464 | } 465 | #[inline] 466 | fn try_size_hint(depth: usize) 467 | -> ::core::result::Result< 468 | (usize, ::core::option::Option), 469 | arbitrary::MaxRecursionReached, 470 | > 471 | { 472 | Ok(arbitrary::size_hint::and( 473 | ::size_hint(depth), 474 | arbitrary::size_hint::try_recursion_guard(depth, |depth| { 475 | Ok(arbitrary::size_hint::or_all(&[ #( #variants? ),* ])) 476 | })?, 477 | )) 478 | } 479 | } 480 | } else { 481 | // The enum is guaranteed non-recursive, i.e. fieldless: `size_hint` is the 482 | // primary one, and the default `try_size_hint` is good enough. 483 | quote! { 484 | fn size_hint(depth: usize) -> (usize, ::core::option::Option) { 485 | ::size_hint(depth) 486 | } 487 | } 488 | } 489 | }), 490 | } 491 | } 492 | 493 | fn gen_constructor_for_field(field: &Field) -> Result { 494 | let ctor = match determine_field_constructor(field)? { 495 | FieldConstructor::Default => quote!(::core::default::Default::default()), 496 | FieldConstructor::Arbitrary => quote!(arbitrary::Arbitrary::arbitrary(u)?), 497 | FieldConstructor::With(function_or_closure) => quote!((#function_or_closure)(u)?), 498 | FieldConstructor::Value(value) => quote!(#value), 499 | }; 500 | Ok(ctor) 501 | } 502 | 503 | fn check_variant_attrs(variant: &Variant) -> Result<()> { 504 | for attr in &variant.attrs { 505 | if attr.path().is_ident(ARBITRARY_ATTRIBUTE_NAME) { 506 | return Err(Error::new_spanned( 507 | attr, 508 | format!( 509 | "invalid `{}` attribute. it is unsupported on enum variants. try applying it to a field of the variant instead", 510 | ARBITRARY_ATTRIBUTE_NAME 511 | ), 512 | )); 513 | } 514 | } 515 | Ok(()) 516 | } 517 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 The Rust Fuzz Project Developers. 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license 5 | // , at your 6 | // option. This file may not be copied, modified, or distributed 7 | // except according to those terms. 8 | 9 | //! The `Arbitrary` trait crate. 10 | //! 11 | //! This trait provides an [`Arbitrary`] trait to 12 | //! produce well-typed, structured values, from raw, byte buffers. It is 13 | //! generally intended to be used with fuzzers like AFL or libFuzzer. See the 14 | //! [`Arbitrary`] trait's documentation for details on 15 | //! automatically deriving, implementing, and/or using the trait. 16 | 17 | #![deny(bad_style)] 18 | #![deny(missing_docs)] 19 | #![deny(future_incompatible)] 20 | #![deny(nonstandard_style)] 21 | #![deny(rust_2018_compatibility)] 22 | #![deny(rust_2018_idioms)] 23 | #![deny(unused)] 24 | 25 | mod error; 26 | mod foreign; 27 | pub mod size_hint; 28 | pub mod unstructured; 29 | 30 | #[cfg(test)] 31 | mod tests; 32 | 33 | pub use error::*; 34 | 35 | #[cfg(feature = "derive_arbitrary")] 36 | pub use derive_arbitrary::*; 37 | 38 | #[doc(inline)] 39 | pub use unstructured::Unstructured; 40 | 41 | /// Error indicating that the maximum recursion depth has been reached while calculating [`Arbitrary::size_hint`]() 42 | #[derive(Debug, Clone)] 43 | #[non_exhaustive] 44 | pub struct MaxRecursionReached {} 45 | 46 | impl core::fmt::Display for MaxRecursionReached { 47 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 48 | f.write_str("Maximum recursion depth has been reached") 49 | } 50 | } 51 | 52 | impl std::error::Error for MaxRecursionReached {} 53 | 54 | /// Generate arbitrary structured values from raw, unstructured data. 55 | /// 56 | /// The `Arbitrary` trait allows you to generate valid structured values, like 57 | /// `HashMap`s, or ASTs, or `MyTomlConfig`, or any other data structure from 58 | /// raw, unstructured bytes provided by a fuzzer. 59 | /// 60 | /// # Deriving `Arbitrary` 61 | /// 62 | /// Automatically deriving the `Arbitrary` trait is the recommended way to 63 | /// implement `Arbitrary` for your types. 64 | /// 65 | /// Using the custom derive requires that you enable the `"derive"` cargo 66 | /// feature in your `Cargo.toml`: 67 | /// 68 | /// ```toml 69 | /// [dependencies] 70 | /// arbitrary = { version = "1", features = ["derive"] } 71 | /// ``` 72 | /// 73 | /// Then, you add the `#[derive(Arbitrary)]` annotation to your `struct` or 74 | /// `enum` type definition: 75 | /// 76 | /// ``` 77 | /// # #[cfg(feature = "derive")] mod foo { 78 | /// use arbitrary::Arbitrary; 79 | /// use std::collections::HashSet; 80 | /// 81 | /// #[derive(Arbitrary)] 82 | /// pub struct AddressBook { 83 | /// friends: HashSet, 84 | /// } 85 | /// 86 | /// #[derive(Arbitrary, Hash, Eq, PartialEq)] 87 | /// pub enum Friend { 88 | /// Buddy { name: String }, 89 | /// Pal { age: usize }, 90 | /// } 91 | /// # } 92 | /// ``` 93 | /// 94 | /// Every member of the `struct` or `enum` must also implement `Arbitrary`. 95 | /// 96 | /// It is also possible to change the default bounds added by the derive: 97 | /// 98 | /// ``` 99 | /// # #[cfg(feature = "derive")] mod foo { 100 | /// use arbitrary::Arbitrary; 101 | /// 102 | /// trait Trait { 103 | /// type Assoc: for<'a> Arbitrary<'a>; 104 | /// } 105 | /// 106 | /// #[derive(Arbitrary)] 107 | /// // The bounds are used verbatim, so any existing trait bounds will need to be repeated. 108 | /// #[arbitrary(bound = "T: Trait")] 109 | /// struct Point { 110 | /// x: T::Assoc, 111 | /// } 112 | /// # } 113 | /// ``` 114 | /// 115 | /// # Implementing `Arbitrary` By Hand 116 | /// 117 | /// Implementing `Arbitrary` mostly involves nested calls to other `Arbitrary` 118 | /// arbitrary implementations for each of your `struct` or `enum`'s members. But 119 | /// sometimes you need some amount of raw data, or you need to generate a 120 | /// variably-sized collection type, or something of that sort. The 121 | /// [`Unstructured`] type helps you with these tasks. 122 | /// 123 | /// ``` 124 | /// # #[cfg(feature = "derive")] mod foo { 125 | /// # pub struct MyCollection { _t: std::marker::PhantomData } 126 | /// # impl MyCollection { 127 | /// # pub fn new() -> Self { MyCollection { _t: std::marker::PhantomData } } 128 | /// # pub fn insert(&mut self, element: T) {} 129 | /// # } 130 | /// use arbitrary::{Arbitrary, Result, Unstructured}; 131 | /// 132 | /// impl<'a, T> Arbitrary<'a> for MyCollection 133 | /// where 134 | /// T: Arbitrary<'a>, 135 | /// { 136 | /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { 137 | /// // Get an iterator of arbitrary `T`s. 138 | /// let iter = u.arbitrary_iter::()?; 139 | /// 140 | /// // And then create a collection! 141 | /// let mut my_collection = MyCollection::new(); 142 | /// for elem_result in iter { 143 | /// let elem = elem_result?; 144 | /// my_collection.insert(elem); 145 | /// } 146 | /// 147 | /// Ok(my_collection) 148 | /// } 149 | /// } 150 | /// # } 151 | /// ``` 152 | /// 153 | /// # A Note On Output Distributions 154 | /// 155 | /// There is no requirement for a particular distribution of the values. For 156 | /// example, it is not required that every value appears with the same 157 | /// probability. That being said, the main use for `Arbitrary` is for fuzzing, 158 | /// so in many cases a uniform distribution will make the most sense in order to 159 | /// provide the best coverage of the domain. In other cases this is not 160 | /// desirable or even possible, for example when sampling from a uniform 161 | /// distribution is computationally expensive or in the case of collections that 162 | /// may grow indefinitely. 163 | pub trait Arbitrary<'a>: Sized { 164 | /// Generate an arbitrary value of `Self` from the given unstructured data. 165 | /// 166 | /// Calling `Arbitrary::arbitrary` requires that you have some raw data, 167 | /// perhaps given to you by a fuzzer like AFL or libFuzzer. You wrap this 168 | /// raw data in an `Unstructured`, and then you can call `::arbitrary` to construct an arbitrary instance of `MyType` 170 | /// from that unstructured data. 171 | /// 172 | /// Implementations may return an error if there is not enough data to 173 | /// construct a full instance of `Self`, or they may fill out the rest of 174 | /// `Self` with dummy values. Using dummy values when the underlying data is 175 | /// exhausted can help avoid accidentally "defeating" some of the fuzzer's 176 | /// mutations to the underlying byte stream that might otherwise lead to 177 | /// interesting runtime behavior or new code coverage if only we had just a 178 | /// few more bytes. However, it also requires that implementations for 179 | /// recursive types (e.g. `struct Foo(Option>)`) avoid infinite 180 | /// recursion when the underlying data is exhausted. 181 | /// 182 | /// ``` 183 | /// # #[cfg(feature = "derive")] fn foo() { 184 | /// use arbitrary::{Arbitrary, Unstructured}; 185 | /// 186 | /// #[derive(Arbitrary)] 187 | /// pub struct MyType { 188 | /// // ... 189 | /// } 190 | /// 191 | /// // Get the raw data from the fuzzer or wherever else. 192 | /// # let get_raw_data_from_fuzzer = || &[]; 193 | /// let raw_data: &[u8] = get_raw_data_from_fuzzer(); 194 | /// 195 | /// // Wrap that raw data in an `Unstructured`. 196 | /// let mut unstructured = Unstructured::new(raw_data); 197 | /// 198 | /// // Generate an arbitrary instance of `MyType` and do stuff with it. 199 | /// if let Ok(value) = MyType::arbitrary(&mut unstructured) { 200 | /// # let do_stuff = |_| {}; 201 | /// do_stuff(value); 202 | /// } 203 | /// # } 204 | /// ``` 205 | /// 206 | /// See also the documentation for [`Unstructured`]. 207 | fn arbitrary(u: &mut Unstructured<'a>) -> Result; 208 | 209 | /// Generate an arbitrary value of `Self` from the entirety of the given 210 | /// unstructured data. 211 | /// 212 | /// This is similar to Arbitrary::arbitrary, however it assumes that it is 213 | /// the last consumer of the given data, and is thus able to consume it all 214 | /// if it needs. See also the documentation for 215 | /// [`Unstructured`]. 216 | fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result { 217 | Self::arbitrary(&mut u) 218 | } 219 | 220 | /// Get a size hint for how many bytes out of an `Unstructured` this type 221 | /// needs to construct itself. 222 | /// 223 | /// This is useful for determining how many elements we should insert when 224 | /// creating an arbitrary collection. 225 | /// 226 | /// The return value is similar to [`Iterator::size_hint`]: it returns a 227 | /// tuple where the first element is a lower bound on the number of bytes 228 | /// required, and the second element is an optional upper bound. 229 | /// 230 | /// The default implementation return `(0, None)` which is correct for any 231 | /// type, but not ultimately that useful. Using `#[derive(Arbitrary)]` will 232 | /// create a better implementation. If you are writing an `Arbitrary` 233 | /// implementation by hand, and your type can be part of a dynamically sized 234 | /// collection (such as `Vec`), you are strongly encouraged to override this 235 | /// default with a better implementation, and also override 236 | /// [`try_size_hint`]. 237 | /// 238 | /// ## How to implement this 239 | /// 240 | /// If the size hint calculation is a trivial constant and does not recurse 241 | /// into any other `size_hint` call, you should implement it in `size_hint`: 242 | /// 243 | /// ``` 244 | /// use arbitrary::{size_hint, Arbitrary, Result, Unstructured}; 245 | /// 246 | /// struct SomeStruct(u8); 247 | /// 248 | /// impl<'a> Arbitrary<'a> for SomeStruct { 249 | /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { 250 | /// let buf = &mut [0]; 251 | /// u.fill_buffer(buf)?; 252 | /// Ok(SomeStruct(buf[0])) 253 | /// } 254 | /// 255 | /// #[inline] 256 | /// fn size_hint(depth: usize) -> (usize, Option) { 257 | /// let _ = depth; 258 | /// (1, Some(1)) 259 | /// } 260 | /// } 261 | /// ``` 262 | /// 263 | /// Otherwise, it should instead be implemented in [`try_size_hint`], 264 | /// and the `size_hint` implementation should forward to it: 265 | /// 266 | /// ``` 267 | /// use arbitrary::{size_hint, Arbitrary, MaxRecursionReached, Result, Unstructured}; 268 | /// 269 | /// struct SomeStruct { 270 | /// a: A, 271 | /// b: B, 272 | /// } 273 | /// 274 | /// impl<'a, A: Arbitrary<'a>, B: Arbitrary<'a>> Arbitrary<'a> for SomeStruct { 275 | /// fn arbitrary(u: &mut Unstructured<'a>) -> Result { 276 | /// // ... 277 | /// # todo!() 278 | /// } 279 | /// 280 | /// fn size_hint(depth: usize) -> (usize, Option) { 281 | /// // Return the value of try_size_hint 282 | /// // 283 | /// // If the recursion fails, return the default, always valid `(0, None)` 284 | /// Self::try_size_hint(depth).unwrap_or_default() 285 | /// } 286 | /// 287 | /// fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 288 | /// // Protect against potential infinite recursion with 289 | /// // `try_recursion_guard`. 290 | /// size_hint::try_recursion_guard(depth, |depth| { 291 | /// // If we aren't too deep, then `recursion_guard` calls 292 | /// // this closure, which implements the natural size hint. 293 | /// // Don't forget to use the new `depth` in all nested 294 | /// // `try_size_hint` calls! We recommend shadowing the 295 | /// // parameter, like what is done here, so that you can't 296 | /// // accidentally use the wrong depth. 297 | /// Ok(size_hint::and( 298 | /// ::try_size_hint(depth)?, 299 | /// ::try_size_hint(depth)?, 300 | /// )) 301 | /// }) 302 | /// } 303 | /// } 304 | /// ``` 305 | /// 306 | /// ## Invariant 307 | /// 308 | /// It must be possible to construct every possible output using only inputs 309 | /// of lengths bounded by these parameters. This applies to both 310 | /// [`Arbitrary::arbitrary`] and [`Arbitrary::arbitrary_take_rest`]. 311 | /// 312 | /// This is trivially true for `(0, None)`. To restrict this further, it 313 | /// must be proven that all inputs that are now excluded produced redundant 314 | /// outputs which are still possible to produce using the reduced input 315 | /// space. 316 | /// 317 | /// [iterator-size-hint]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.size_hint 318 | /// [`try_size_hint`]: Arbitrary::try_size_hint 319 | #[inline] 320 | fn size_hint(depth: usize) -> (usize, Option) { 321 | let _ = depth; 322 | (0, None) 323 | } 324 | 325 | /// Get a size hint for how many bytes out of an `Unstructured` this type 326 | /// needs to construct itself. 327 | /// 328 | /// Unlike [`size_hint`], this function keeps the information that the 329 | /// recursion limit was reached. This is required to "short circuit" the 330 | /// calculation and avoid exponential blowup with recursive structures. 331 | /// 332 | /// If you are implementing [`size_hint`] for a struct that could be 333 | /// recursive, you should implement `try_size_hint` and call the 334 | /// `try_size_hint` when recursing 335 | /// 336 | /// 337 | /// The return value is similar to [`core::iter::Iterator::size_hint`]: it 338 | /// returns a tuple where the first element is a lower bound on the number 339 | /// of bytes required, and the second element is an optional upper bound. 340 | /// 341 | /// The default implementation returns the value of [`size_hint`] which is 342 | /// correct for any type, but might lead to exponential blowup when dealing 343 | /// with recursive types. 344 | /// 345 | /// ## Invariant 346 | /// 347 | /// It must be possible to construct every possible output using only inputs 348 | /// of lengths bounded by these parameters. This applies to both 349 | /// [`Arbitrary::arbitrary`] and [`Arbitrary::arbitrary_take_rest`]. 350 | /// 351 | /// This is trivially true for `(0, None)`. To restrict this further, it 352 | /// must be proven that all inputs that are now excluded produced redundant 353 | /// outputs which are still possible to produce using the reduced input 354 | /// space. 355 | /// 356 | /// ## When to implement `try_size_hint` 357 | /// 358 | /// If you 100% know that the type you are implementing `Arbitrary` for is 359 | /// not a recursive type, or your implementation is not transitively calling 360 | /// any other `size_hint` methods, you may implement [`size_hint`], and the 361 | /// default `try_size_hint` implementation will use it. 362 | /// 363 | /// Note that if you are implementing `Arbitrary` for a generic type, you 364 | /// cannot guarantee the lack of type recursion! 365 | /// 366 | /// Otherwise, when there is possible type recursion, you should implement 367 | /// `try_size_hint` instead. 368 | /// 369 | /// ## The `depth` parameter 370 | /// 371 | /// When implementing `try_size_hint`, you need to use 372 | /// [`arbitrary::size_hint::try_recursion_guard(depth)`][crate::size_hint::try_recursion_guard] 373 | /// to prevent potential infinite recursion when calculating size hints for 374 | /// potentially recursive types: 375 | /// 376 | /// ``` 377 | /// use arbitrary::{size_hint, Arbitrary, MaxRecursionReached, Unstructured}; 378 | /// 379 | /// // This can potentially be a recursive type if `L` or `R` contain 380 | /// // something like `Box>>`! 381 | /// enum MyEither { 382 | /// Left(L), 383 | /// Right(R), 384 | /// } 385 | /// 386 | /// impl<'a, L, R> Arbitrary<'a> for MyEither 387 | /// where 388 | /// L: Arbitrary<'a>, 389 | /// R: Arbitrary<'a>, 390 | /// { 391 | /// fn arbitrary(u: &mut Unstructured) -> arbitrary::Result { 392 | /// // ... 393 | /// # unimplemented!() 394 | /// } 395 | /// 396 | /// fn size_hint(depth: usize) -> (usize, Option) { 397 | /// // Return the value of `try_size_hint` 398 | /// // 399 | /// // If the recursion fails, return the default `(0, None)` range, 400 | /// // which is always valid. 401 | /// Self::try_size_hint(depth).unwrap_or_default() 402 | /// } 403 | /// 404 | /// fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 405 | /// // Protect against potential infinite recursion with 406 | /// // `try_recursion_guard`. 407 | /// size_hint::try_recursion_guard(depth, |depth| { 408 | /// // If we aren't too deep, then `recursion_guard` calls 409 | /// // this closure, which implements the natural size hint. 410 | /// // Don't forget to use the new `depth` in all nested 411 | /// // `try_size_hint` calls! We recommend shadowing the 412 | /// // parameter, like what is done here, so that you can't 413 | /// // accidentally use the wrong depth. 414 | /// Ok(size_hint::or( 415 | /// ::try_size_hint(depth)?, 416 | /// ::try_size_hint(depth)?, 417 | /// )) 418 | /// }) 419 | /// } 420 | /// } 421 | /// ``` 422 | #[inline] 423 | fn try_size_hint(depth: usize) -> Result<(usize, Option), MaxRecursionReached> { 424 | Ok(Self::size_hint(depth)) 425 | } 426 | } 427 | 428 | #[cfg(test)] 429 | mod test { 430 | use super::*; 431 | 432 | #[test] 433 | fn exhausted_entropy() { 434 | let mut u = Unstructured::new(&[]); 435 | assert_eq!(u.arbitrary::().unwrap(), false); 436 | assert_eq!(u.arbitrary::().unwrap(), 0); 437 | assert_eq!(u.arbitrary::().unwrap(), 0); 438 | assert_eq!(u.arbitrary::().unwrap(), 0.0); 439 | assert_eq!(u.arbitrary::().unwrap(), 0.0); 440 | assert_eq!(u.arbitrary::>().unwrap(), None); 441 | assert_eq!(u.int_in_range(4..=100).unwrap(), 4); 442 | assert_eq!(u.choose_index(10).unwrap(), 0); 443 | assert_eq!(u.ratio(5, 7).unwrap(), true); 444 | } 445 | } 446 | 447 | /// Multiple conflicting arbitrary attributes are used on the same field: 448 | /// ```compile_fail 449 | /// #[derive(::arbitrary::Arbitrary)] 450 | /// struct Point { 451 | /// #[arbitrary(value = 2)] 452 | /// #[arbitrary(value = 2)] 453 | /// x: i32, 454 | /// } 455 | /// ``` 456 | /// 457 | /// An unknown attribute: 458 | /// ```compile_fail 459 | /// #[derive(::arbitrary::Arbitrary)] 460 | /// struct Point { 461 | /// #[arbitrary(unknown_attr)] 462 | /// x: i32, 463 | /// } 464 | /// ``` 465 | /// 466 | /// An unknown attribute with a value: 467 | /// ```compile_fail 468 | /// #[derive(::arbitrary::Arbitrary)] 469 | /// struct Point { 470 | /// #[arbitrary(unknown_attr = 13)] 471 | /// x: i32, 472 | /// } 473 | /// ``` 474 | /// 475 | /// `value` without RHS: 476 | /// ```compile_fail 477 | /// #[derive(::arbitrary::Arbitrary)] 478 | /// struct Point { 479 | /// #[arbitrary(value)] 480 | /// x: i32, 481 | /// } 482 | /// ``` 483 | /// 484 | /// `with` without RHS: 485 | /// ```compile_fail 486 | /// #[derive(::arbitrary::Arbitrary)] 487 | /// struct Point { 488 | /// #[arbitrary(with)] 489 | /// x: i32, 490 | /// } 491 | /// ``` 492 | /// 493 | /// Multiple conflicting bounds at the container-level: 494 | /// ```compile_fail 495 | /// #[derive(::arbitrary::Arbitrary)] 496 | /// #[arbitrary(bound = "T: Default")] 497 | /// #[arbitrary(bound = "T: Default")] 498 | /// struct Point { 499 | /// #[arbitrary(default)] 500 | /// x: T, 501 | /// } 502 | /// ``` 503 | /// 504 | /// Multiple conflicting bounds in a single bound attribute: 505 | /// ```compile_fail 506 | /// #[derive(::arbitrary::Arbitrary)] 507 | /// #[arbitrary(bound = "T: Default, T: Default")] 508 | /// struct Point { 509 | /// #[arbitrary(default)] 510 | /// x: T, 511 | /// } 512 | /// ``` 513 | /// 514 | /// Multiple conflicting bounds in multiple bound attributes: 515 | /// ```compile_fail 516 | /// #[derive(::arbitrary::Arbitrary)] 517 | /// #[arbitrary(bound = "T: Default", bound = "T: Default")] 518 | /// struct Point { 519 | /// #[arbitrary(default)] 520 | /// x: T, 521 | /// } 522 | /// ``` 523 | /// 524 | /// Too many bounds supplied: 525 | /// ```compile_fail 526 | /// #[derive(::arbitrary::Arbitrary)] 527 | /// #[arbitrary(bound = "T: Default")] 528 | /// struct Point { 529 | /// x: i32, 530 | /// } 531 | /// ``` 532 | /// 533 | /// Too many bounds supplied across multiple attributes: 534 | /// ```compile_fail 535 | /// #[derive(::arbitrary::Arbitrary)] 536 | /// #[arbitrary(bound = "T: Default")] 537 | /// #[arbitrary(bound = "U: Default")] 538 | /// struct Point { 539 | /// #[arbitrary(default)] 540 | /// x: T, 541 | /// } 542 | /// ``` 543 | /// 544 | /// Attempt to use the derive attribute on an enum variant: 545 | /// ```compile_fail 546 | /// #[derive(::arbitrary::Arbitrary)] 547 | /// enum Enum { 548 | /// #[arbitrary(default)] 549 | /// Variant(T), 550 | /// } 551 | /// ``` 552 | #[cfg(all(doctest, feature = "derive"))] 553 | pub struct CompileFailTests; 554 | 555 | // Support for `#[derive(Arbitrary)]`. 556 | #[doc(hidden)] 557 | #[cfg(feature = "derive")] 558 | pub mod details { 559 | use super::*; 560 | 561 | // Hidden trait that papers over the difference between `&mut Unstructured` and 562 | // `Unstructured` arguments so that `with_recursive_count` can be used for both 563 | // `arbitrary` and `arbitrary_take_rest`. 564 | pub trait IsEmpty { 565 | fn is_empty(&self) -> bool; 566 | } 567 | 568 | impl IsEmpty for Unstructured<'_> { 569 | fn is_empty(&self) -> bool { 570 | Unstructured::is_empty(self) 571 | } 572 | } 573 | 574 | impl IsEmpty for &mut Unstructured<'_> { 575 | fn is_empty(&self) -> bool { 576 | Unstructured::is_empty(self) 577 | } 578 | } 579 | 580 | // Calls `f` with a recursive count guard. 581 | #[inline] 582 | pub fn with_recursive_count( 583 | u: U, 584 | recursive_count: &'static std::thread::LocalKey>, 585 | f: impl FnOnce(U) -> Result, 586 | ) -> Result { 587 | let guard_against_recursion = u.is_empty(); 588 | if guard_against_recursion { 589 | recursive_count.with(|count| { 590 | if count.get() > 0 { 591 | return Err(Error::NotEnoughData); 592 | } 593 | count.set(count.get() + 1); 594 | Ok(()) 595 | })?; 596 | } 597 | 598 | let result = f(u); 599 | 600 | if guard_against_recursion { 601 | recursive_count.with(|count| { 602 | count.set(count.get() - 1); 603 | }); 604 | } 605 | 606 | result 607 | } 608 | } 609 | --------------------------------------------------------------------------------