aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-06-21 12:05:54 -0700
committerJoel Galenson <jgalenson@google.com>2021-06-21 12:05:54 -0700
commite0b2b28ae4a9ecfd299dd80de58fc7ec17e8f0c5 (patch)
treef2191863eba0b1e38e27936acf7bd3ff56edac4f
parente28af0befb7c8de39febbd271d3812bbc51aaf90 (diff)
downloadarbitrary-e0b2b28ae4a9ecfd299dd80de58fc7ec17e8f0c5.tar.gz
Test: make Change-Id: I4d3c5bf08f887ced41873b35a0aeaee174db5711
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp2
-rw-r--r--CHANGELOG.md15
-rw-r--r--Cargo.toml2
-rw-r--r--Cargo.toml.orig2
-rw-r--r--METADATA8
-rw-r--r--README.md2
-rw-r--r--src/lib.rs181
-rw-r--r--src/unstructured.rs24
9 files changed, 175 insertions, 63 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index cfe44cd..262c88c 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "83b852c9bba47359ad33fc5b1f81f29425bc97e8"
+ "sha1": "5ec3b33f05e8e993688ab872ca5e1a24f4802ebe"
}
}
diff --git a/Android.bp b/Android.bp
index 8a65b0d..e3be286 100644
--- a/Android.bp
+++ b/Android.bp
@@ -54,5 +54,5 @@ rust_library_rlib {
// derive_arbitrary-1.0.1
// proc-macro2-1.0.27 "default,proc-macro"
// quote-1.0.9 "default,proc-macro"
-// syn-1.0.72 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+// syn-1.0.73 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
// unicode-xid-0.2.2 "default"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6542d53..54dc917 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,21 @@ Released YYYY-MM-DD.
* TODO (or remove section if none)
+## 1.0.1
+
+Released 2021-05-20.
+
+### Added
+
+* `Arbitrary` impls for `NonZeroX` types [#79](https://github.com/rust-fuzz/arbitrary/pull/79)
+* `Arbitrary` impls for all arrays using const generics [#55](https://github.com/rust-fuzz/arbitrary/pull/55)
+* `Arbitrary` impls for `Ipv4Addr` and `Ipv6Addr` [#84](https://github.com/rust-fuzz/arbitrary/pull/84)
+
+### Fixed
+
+* Use fewer bytes for `Unstructured::int_in_range()` [#80](https://github.com/rust-fuzz/arbitrary/pull/80)
+* Use correct range for `char` generation [#83](https://github.com/rust-fuzz/arbitrary/pull/83)
+
--------------------------------------------------------------------------------
## 1.0.0
diff --git a/Cargo.toml b/Cargo.toml
index b57a351..1e8eb7a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "arbitrary"
-version = "1.0.0"
+version = "1.0.1"
authors = ["The Rust-Fuzz Project Developers", "Nick Fitzgerald <fitzgen@gmail.com>", "Manish Goregaokar <manishsmail@gmail.com>", "Simonas Kazlauskas <arbitrary@kazlauskas.me>", "Brian L. Troutwine <brian@troutwine.us>", "Corey Farwell <coreyf@rwell.org>"]
description = "The trait for generating structured data from unstructured data"
documentation = "https://docs.rs/arbitrary/"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index f177ed4..e7f7951 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "arbitrary"
-version = "1.0.0" # Make sure this matches the derive crate version
+version = "1.0.1" # Make sure this matches the derive crate version
authors = [
"The Rust-Fuzz Project Developers",
"Nick Fitzgerald <fitzgen@gmail.com>",
diff --git a/METADATA b/METADATA
index 1029866..132c33c 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/arbitrary/arbitrary-1.0.0.crate"
+ value: "https://static.crates.io/crates/arbitrary/arbitrary-1.0.1.crate"
}
- version: "1.0.0"
+ version: "1.0.1"
license_type: NOTICE
last_upgrade_date {
year: 2021
- month: 4
- day: 1
+ month: 6
+ day: 21
}
}
diff --git a/README.md b/README.md
index fce547a..38bd949 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
## About
-The `Arbitrary` crate lets you construct arbitrary instance of a type.
+The `Arbitrary` crate lets you construct arbitrary instances of a type.
This crate is primarily intended to be combined with a fuzzer like [libFuzzer
and `cargo-fuzz`](https://github.com/rust-fuzz/cargo-fuzz) or
diff --git a/src/lib.rs b/src/lib.rs
index 48898a8..fef2620 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,12 +37,15 @@ pub mod size_hint;
use core::cell::{Cell, RefCell, UnsafeCell};
use core::iter;
use core::mem;
+use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
+use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
use core::ops::{Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
use core::str;
use core::time::Duration;
use std::borrow::{Cow, ToOwned};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
use std::ffi::{CString, OsString};
+use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize};
@@ -204,7 +207,7 @@ pub trait Arbitrary<'a>: Sized {
/// not a recursive type, or your implementation is not transitively calling
/// any other `size_hint` methods, you can ignore the `depth` parameter.
/// Note that if you are implementing `Arbitrary` for a generic type, you
- /// cannot guarantee the lack of type recrusion!
+ /// cannot guarantee the lack of type recursion!
///
/// Otherwise, you need to use
/// [`arbitrary::size_hint::recursion_guard(depth)`][crate::size_hint::recursion_guard]
@@ -345,12 +348,13 @@ impl_arbitrary_for_floats! {
impl<'a> Arbitrary<'a> for char {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
use std::char;
- const CHAR_END: u32 = 0x0011_000;
+ // The highest unicode code point is 0x11_FFFF
+ const CHAR_END: u32 = 0x11_0000;
// The size of the surrogate blocks
const SURROGATES_START: u32 = 0xD800;
let mut c = <u32 as Arbitrary<'a>>::arbitrary(u)? % CHAR_END;
if let Some(c) = char::from_u32(c) {
- return Ok(c);
+ Ok(c)
} else {
// We found a surrogate, wrap and try again
c -= SURROGATES_START;
@@ -571,61 +575,91 @@ macro_rules! arbitrary_tuple {
}
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);
-macro_rules! arbitrary_array {
- {$n:expr, ($t:ident, $a:ident) $(($ts:ident, $as:ident))*} => {
- arbitrary_array!{($n - 1), $(($ts, $as))*}
-
- impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; $n] {
- fn arbitrary(u: &mut Unstructured<'a>) -> Result<[T; $n]> {
- Ok([
- Arbitrary::arbitrary(u)?,
- $(<$ts as Arbitrary>::arbitrary(u)?),*
- ])
- }
-
- #[allow(unused_mut)]
- fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<[T; $n]> {
- $(let $as = $ts::arbitrary(&mut u)?;)*
- let last = Arbitrary::arbitrary_take_rest(u)?;
+// Helper to safely create arrays since the standard library doesn't
+// provide one yet. Shouldn't be necessary in the future.
+struct ArrayGuard<T, const N: usize> {
+ dst: *mut T,
+ initialized: usize,
+}
- Ok([
- $($as,)* last
- ])
- }
+impl<T, const N: usize> Drop for ArrayGuard<T, N> {
+ fn drop(&mut self) {
+ debug_assert!(self.initialized <= N);
+ let initialized_part = core::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
+ unsafe {
+ core::ptr::drop_in_place(initialized_part);
+ }
+ }
+}
- #[inline]
- fn size_hint(depth: usize) -> (usize, Option<usize>) {
- crate::size_hint::and_all(&[
- <$t as Arbitrary>::size_hint(depth),
- $( <$ts as Arbitrary>::size_hint(depth) ),*
- ])
- }
+fn create_array<F, T, const N: usize>(mut cb: F) -> [T; N]
+where
+ F: FnMut(usize) -> T,
+{
+ let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
+ let array_ptr = array.as_mut_ptr();
+ let dst = array_ptr as _;
+ let mut guard: ArrayGuard<T, N> = ArrayGuard {
+ dst,
+ initialized: 0,
+ };
+ unsafe {
+ for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
+ core::ptr::write(value_ptr, cb(idx));
+ guard.initialized += 1;
}
+ mem::forget(guard);
+ array.assume_init()
+ }
+}
+
+fn try_create_array<F, T, const N: usize>(mut cb: F) -> Result<[T; N]>
+where
+ F: FnMut(usize) -> Result<T>,
+{
+ let mut array: mem::MaybeUninit<[T; N]> = mem::MaybeUninit::uninit();
+ let array_ptr = array.as_mut_ptr();
+ let dst = array_ptr as _;
+ let mut guard: ArrayGuard<T, N> = ArrayGuard {
+ dst,
+ initialized: 0,
};
- ($n: expr,) => {};
+ unsafe {
+ for (idx, value_ptr) in (&mut *array.as_mut_ptr()).iter_mut().enumerate() {
+ core::ptr::write(value_ptr, cb(idx)?);
+ guard.initialized += 1;
+ }
+ mem::forget(guard);
+ Ok(array.assume_init())
+ }
}
-impl<'a, T: Arbitrary<'a>> Arbitrary<'a> for [T; 0] {
- fn arbitrary(_: &mut Unstructured<'a>) -> Result<[T; 0]> {
- Ok([])
+impl<'a, T, const N: usize> Arbitrary<'a> for [T; N]
+where
+ T: Arbitrary<'a>,
+{
+ #[inline]
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ try_create_array(|_| <T as Arbitrary<'a>>::arbitrary(u))
}
- fn arbitrary_take_rest(_: Unstructured<'a>) -> Result<[T; 0]> {
- Ok([])
+ #[inline]
+ fn arbitrary_take_rest(mut u: Unstructured<'a>) -> Result<Self> {
+ let mut array = Self::arbitrary(&mut u)?;
+ if let Some(last) = array.last_mut() {
+ *last = Arbitrary::arbitrary_take_rest(u)?;
+ }
+ Ok(array)
}
#[inline]
- fn size_hint(_: usize) -> (usize, Option<usize>) {
- crate::size_hint::and_all(&[])
+ fn size_hint(d: usize) -> (usize, Option<usize>) {
+ crate::size_hint::and_all(&create_array::<_, (usize, Option<usize>), N>(|_| {
+ <T as Arbitrary>::size_hint(d)
+ }))
}
}
-arbitrary_array! { 32, (T, a) (T, b) (T, c) (T, d) (T, e) (T, f) (T, g) (T, h)
-(T, i) (T, j) (T, k) (T, l) (T, m) (T, n) (T, o) (T, p)
-(T, q) (T, r) (T, s) (T, u) (T, v) (T, w) (T, x) (T, y)
-(T, z) (T, aa) (T, ab) (T, ac) (T, ad) (T, ae) (T, af)
-(T, ag) }
-
impl<'a> Arbitrary<'a> for &'a [u8] {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
let len = u.arbitrary_len::<u8>()?;
@@ -872,7 +906,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Box<A> {
#[inline]
fn size_hint(depth: usize) -> (usize, Option<usize>) {
- crate::size_hint::recursion_guard(depth, |depth| <A as Arbitrary>::size_hint(depth))
+ crate::size_hint::recursion_guard(depth, <A as Arbitrary>::size_hint)
}
}
@@ -918,7 +952,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Arc<A> {
#[inline]
fn size_hint(depth: usize) -> (usize, Option<usize>) {
- crate::size_hint::recursion_guard(depth, |depth| <A as Arbitrary>::size_hint(depth))
+ crate::size_hint::recursion_guard(depth, <A as Arbitrary>::size_hint)
}
}
@@ -929,7 +963,7 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for Rc<A> {
#[inline]
fn size_hint(depth: usize) -> (usize, Option<usize>) {
- crate::size_hint::recursion_guard(depth, |depth| <A as Arbitrary>::size_hint(depth))
+ crate::size_hint::recursion_guard(depth, <A as Arbitrary>::size_hint)
}
}
@@ -1010,6 +1044,59 @@ impl<'a, A: Arbitrary<'a>> Arbitrary<'a> for ::std::num::Wrapping<A> {
}
}
+macro_rules! implement_nonzero_int {
+ ($nonzero:ty, $int:ty) => {
+ impl<'a> Arbitrary<'a> for $nonzero {
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ match Self::new(<$int as Arbitrary<'a>>::arbitrary(u)?) {
+ Some(n) => Ok(n),
+ None => Err(Error::IncorrectFormat),
+ }
+ }
+
+ #[inline]
+ fn size_hint(depth: usize) -> (usize, Option<usize>) {
+ <$int as Arbitrary<'a>>::size_hint(depth)
+ }
+ }
+ };
+}
+
+implement_nonzero_int! { NonZeroI8, i8 }
+implement_nonzero_int! { NonZeroI16, i16 }
+implement_nonzero_int! { NonZeroI32, i32 }
+implement_nonzero_int! { NonZeroI64, i64 }
+implement_nonzero_int! { NonZeroI128, i128 }
+implement_nonzero_int! { NonZeroIsize, isize }
+implement_nonzero_int! { NonZeroU8, u8 }
+implement_nonzero_int! { NonZeroU16, u16 }
+implement_nonzero_int! { NonZeroU32, u32 }
+implement_nonzero_int! { NonZeroU64, u64 }
+implement_nonzero_int! { NonZeroU128, u128 }
+implement_nonzero_int! { NonZeroUsize, usize }
+
+impl<'a> Arbitrary<'a> for Ipv4Addr {
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ Ok(Ipv4Addr::from(u32::arbitrary(u)?))
+ }
+
+ #[inline]
+ fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+ (4, Some(4))
+ }
+}
+
+impl<'a> Arbitrary<'a> for Ipv6Addr {
+ fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
+ Ok(Ipv6Addr::from(u128::arbitrary(u)?))
+ }
+
+ #[inline]
+ fn size_hint(_depth: usize) -> (usize, Option<usize>) {
+ (16, Some(16))
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
diff --git a/src/unstructured.rs b/src/unstructured.rs
index 9e2f497..968d41a 100644
--- a/src/unstructured.rs
+++ b/src/unstructured.rs
@@ -221,7 +221,7 @@ impl<'a> Unstructured<'a> {
}
fn arbitrary_byte_size(&mut self) -> Result<usize> {
- if self.data.len() == 0 {
+ if self.data.is_empty() {
Ok(0)
} else if self.data.len() == 1 {
self.data = &[];
@@ -322,7 +322,7 @@ impl<'a> Unstructured<'a> {
let mut offset: usize = 0;
while offset < mem::size_of::<T>()
- && (range >> T::Widest::from_usize(offset)) > T::Widest::ZERO
+ && (range >> T::Widest::from_usize(offset * 8)) > T::Widest::ZERO
{
let byte = bytes.next().ok_or(Error::NotEnoughData)?;
result = (result << 8) | T::Widest::from_u8(byte);
@@ -405,11 +405,9 @@ impl<'a> Unstructured<'a> {
/// ```
pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()> {
let n = std::cmp::min(buffer.len(), self.data.len());
- for i in 0..n {
- buffer[i] = self.data[i];
- }
- for i in self.data.len()..buffer.len() {
- buffer[i] = 0;
+ buffer[..n].copy_from_slice(&self.data[..n]);
+ for byte in buffer[n..].iter_mut() {
+ *byte = 0;
}
self.data = &self.data[n..];
Ok(())
@@ -701,4 +699,16 @@ mod tests {
let choice = *u.choose(&[42]).unwrap();
assert_eq!(choice, 42)
}
+
+ #[test]
+ fn int_in_range_uses_minimal_amount_of_bytes() {
+ let mut u = Unstructured::new(&[1]);
+ u.int_in_range::<u8>(0..=u8::MAX).unwrap();
+
+ let mut u = Unstructured::new(&[1]);
+ u.int_in_range::<u32>(0..=u8::MAX as u32).unwrap();
+
+ let mut u = Unstructured::new(&[1]);
+ u.int_in_range::<u32>(0..=u8::MAX as u32 + 1).unwrap_err();
+ }
}