arbitrary::unstructured

Struct Unstructured

Source
pub struct Unstructured<'a> { /* private fields */ }
Expand description

A source of unstructured data.

An Unstructured helps Arbitrary implementations interpret raw data (typically provided by a fuzzer) as a “DNA string” that describes how to construct the Arbitrary type. The goal is that a small change to the “DNA string” (the raw data wrapped by an Unstructured) results in a small change to the generated Arbitrary instance. This helps a fuzzer efficiently explore the Arbitrary’s input space.

Unstructured is deterministic: given the same raw data, the same series of API calls will return the same results (modulo system resource constraints, like running out of memory). However, Unstructured does not guarantee anything beyond that: it makes not guarantee that it will yield bytes from the underlying data in any particular order.

You shouldn’t generally need to use an Unstructured unless you are writing a custom Arbitrary implementation by hand, instead of deriving it. Mostly, you should just be passing it through to nested Arbitrary::arbitrary calls.

§Example

Imagine you were writing a color conversion crate. You might want to write fuzz tests that take a random RGB color and assert various properties, run functions and make sure nothing panics, etc.

Below is what translating the fuzzer’s raw input into an Unstructured and using that to generate an arbitrary RGB color might look like:

use arbitrary::{Arbitrary, Unstructured};

/// An RGB color.
#[derive(Arbitrary)]
pub struct Rgb {
    r: u8,
    g: u8,
    b: u8,
}

// Get the raw bytes from the fuzzer.
let raw_data: &[u8] = get_input_from_fuzzer();

// Wrap it in an `Unstructured`.
let mut unstructured = Unstructured::new(raw_data);

// Generate an `Rgb` color and run our checks.
if let Ok(rgb) = Rgb::arbitrary(&mut unstructured) {
    run_my_color_conversion_checks(rgb);
}

Implementations§

Source§

impl<'a> Unstructured<'a>

Source

pub fn new(data: &'a [u8]) -> Self

Create a new Unstructured from the given raw data.

§Example
use arbitrary::Unstructured;

let u = Unstructured::new(&[1, 2, 3, 4]);
Source

pub fn len(&self) -> usize

Get the number of remaining bytes of underlying data that are still available.

§Example
use arbitrary::{Arbitrary, Unstructured};

let mut u = Unstructured::new(&[1, 2, 3]);

// Initially have three bytes of data.
assert_eq!(u.len(), 3);

// Generating a `bool` consumes one byte from the underlying data, so
// we are left with two bytes afterwards.
let _ = bool::arbitrary(&mut u);
assert_eq!(u.len(), 2);
Source

pub fn is_empty(&self) -> bool

Is the underlying unstructured data exhausted?

unstructured.is_empty() is the same as unstructured.len() == 0.

§Example
use arbitrary::{Arbitrary, Unstructured};

let mut u = Unstructured::new(&[1, 2, 3, 4]);

// Initially, we are not empty.
assert!(!u.is_empty());

// Generating a `u32` consumes all four bytes of the underlying data, so
// we become empty afterwards.
let _ = u32::arbitrary(&mut u);
assert!(u.is_empty());
Source

pub fn arbitrary<A>(&mut self) -> Result<A>
where A: Arbitrary<'a>,

Generate an arbitrary instance of A.

This is simply a helper method that is equivalent to <A as Arbitrary>::arbitrary(self). This helper is a little bit more concise, and can be used in situations where Rust’s type inference will figure out what A should be.

§Example
use arbitrary::{Arbitrary, Unstructured};

#[derive(Arbitrary)]
struct MyType {
    // ...
}

fn do_stuff(value: MyType) {
    // ...
}

let mut u = Unstructured::new(&[1, 2, 3, 4]);

// Rust's type inference can figure out that `value` should be of type
// `MyType` here:
let value = u.arbitrary()?;
do_stuff(value);
Source

pub fn arbitrary_len<ElementType>(&mut self) -> Result<usize>
where ElementType: Arbitrary<'a>,

Get the number of elements to insert when building up a collection of arbitrary ElementTypes.

This uses the <ElementType as Arbitrary>::size_hint method to smartly choose a length such that we most likely have enough underlying bytes to construct that many arbitrary ElementTypes.

This should only be called within an Arbitrary implementation.

§Example
use arbitrary::{Arbitrary, Result, Unstructured};

impl<'a, T> Arbitrary<'a> for MyCollection<T>
where
    T: Arbitrary<'a>,
{
    fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self> {
        // Get the number of `T`s we should insert into our collection.
        let len = u.arbitrary_len::<T>()?;

        // And then create a collection of that length!
        let mut my_collection = MyCollection::with_capacity(len);
        for _ in 0..len {
            let element = T::arbitrary(u)?;
            my_collection.insert(element);
        }

        Ok(my_collection)
    }
}
Source

pub fn int_in_range<T>(&mut self, range: RangeInclusive<T>) -> Result<T>
where T: Int,

Generate an integer within the given range.

Do not use this to generate the size of a collection. Use arbitrary_len instead.

§Panics

Panics if range.start >= range.end. That is, the given range must be non-empty.

§Example
use arbitrary::{Arbitrary, Unstructured};

let mut u = Unstructured::new(&[1, 2, 3, 4]);

let x: i32 = u.int_in_range(-5_000..=-1_000)
    .expect("constructed `u` with enough bytes to generate an `i32`");

assert!(-5_000 <= x);
assert!(x <= -1_000);
Source

pub fn choose<'b, T>(&mut self, choices: &'b [T]) -> Result<&'b T>

Choose one of the given choices.

This should only be used inside of Arbitrary implementations.

Returns an error if there is not enough underlying data to make a choice or if no choices are provided.

§Examples

Selecting from an array of choices:

use arbitrary::Unstructured;

let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
let choices = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

let choice = u.choose(&choices).unwrap();

println!("chose {}", choice);

An error is returned if no choices are provided:

use arbitrary::Unstructured;

let mut u = Unstructured::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
let choices: [char; 0] = [];

let result = u.choose(&choices);

assert!(result.is_err());
Source

pub fn fill_buffer(&mut self, buffer: &mut [u8]) -> Result<()>

Fill a buffer with bytes from the underlying raw data.

This should only be called within an Arbitrary implementation. This is a very low-level operation. You should generally prefer calling nested Arbitrary implementations like <Vec<u8>>::arbitrary and String::arbitrary over using this method directly.

If this Unstructured does not have enough underlying data to fill the whole buffer, it pads the buffer out with zeros.

§Example
use arbitrary::Unstructured;

let mut u = Unstructured::new(&[1, 2, 3, 4]);

let mut buf = [0; 2];

assert!(u.fill_buffer(&mut buf).is_ok());
assert_eq!(buf, [1, 2]);

assert!(u.fill_buffer(&mut buf).is_ok());
assert_eq!(buf, [3, 4]);

assert!(u.fill_buffer(&mut buf).is_ok());
assert_eq!(buf, [0, 0]);
Source

pub fn bytes(&mut self, size: usize) -> Result<&'a [u8]>

Provide size bytes from the underlying raw data.

This should only be called within an Arbitrary implementation. This is a very low-level operation. You should generally prefer calling nested Arbitrary implementations like <Vec<u8>>::arbitrary and String::arbitrary over using this method directly.

§Example
use arbitrary::Unstructured;

let mut u = Unstructured::new(&[1, 2, 3, 4]);

assert!(u.bytes(2).unwrap() == &[1, 2]);
assert!(u.bytes(2).unwrap() == &[3, 4]);
Source

pub fn peek_bytes(&self, size: usize) -> Option<&'a [u8]>

Peek at size number of bytes of the underlying raw input.

Does not consume the bytes, only peeks at them.

Returns None if there are not size bytes left in the underlying raw input.

§Example
use arbitrary::Unstructured;

let u = Unstructured::new(&[1, 2, 3]);

assert_eq!(u.peek_bytes(0).unwrap(), []);
assert_eq!(u.peek_bytes(1).unwrap(), [1]);
assert_eq!(u.peek_bytes(2).unwrap(), [1, 2]);
assert_eq!(u.peek_bytes(3).unwrap(), [1, 2, 3]);

assert!(u.peek_bytes(4).is_none());
Source

pub fn take_rest(self) -> &'a [u8]

Consume all of the rest of the remaining underlying bytes.

Returns a slice of all the remaining, unconsumed bytes.

§Example
use arbitrary::Unstructured;

let mut u = Unstructured::new(&[1, 2, 3]);

let mut remaining = u.take_rest();

assert_eq!(remaining, [1, 2, 3]);
Source

pub fn arbitrary_iter<'b, ElementType: Arbitrary<'a>>( &'b mut self, ) -> Result<ArbitraryIter<'a, 'b, ElementType>>

Provide an iterator over elements for constructing a collection

This is useful for implementing Arbitrary::arbitrary on collections since the implementation is simply u.arbitrary_iter()?.collect()

Source

pub fn arbitrary_take_rest_iter<ElementType: Arbitrary<'a>>( self, ) -> Result<ArbitraryTakeRestIter<'a, ElementType>>

Provide an iterator over elements for constructing a collection from all the remaining bytes.

This is useful for implementing Arbitrary::arbitrary_take_rest on collections since the implementation is simply u.arbitrary_take_rest_iter()?.collect()

Auto Trait Implementations§

§

impl<'a> Freeze for Unstructured<'a>

§

impl<'a> RefUnwindSafe for Unstructured<'a>

§

impl<'a> Send for Unstructured<'a>

§

impl<'a> Sync for Unstructured<'a>

§

impl<'a> Unpin for Unstructured<'a>

§

impl<'a> UnwindSafe for Unstructured<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.