Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,13 @@ jobs:
run: cargo install cargo-fuzz
- name: "Fuzz for 3 minutes"
run: cargo fuzz run int_in_range -- -max_total_time=$((3 * 60))
no_std_build:
name: no_std Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: rustup update
- run: cargo build --verbose --no-default-features
- run: cargo test --verbose --no-default-features
- run: cargo build --verbose --no-default-features --features=alloc
- run: cargo test --verbose --no-default-features --features=alloc
16 changes: 10 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
name = "arbitrary"
version = "1.4.2" # Make sure this matches the derive crate version (not including the patch version)
authors = [
"The Rust-Fuzz Project Developers",
"Nick Fitzgerald <[email protected]>",
"Manish Goregaokar <[email protected]>",
"Simonas Kazlauskas <[email protected]>",
"Brian L. Troutwine <[email protected]>",
"Corey Farwell <[email protected]>",
"The Rust-Fuzz Project Developers",
"Nick Fitzgerald <[email protected]>",
"Manish Goregaokar <[email protected]>",
"Simonas Kazlauskas <[email protected]>",
"Brian L. Troutwine <[email protected]>",
"Corey Farwell <[email protected]>",
]
categories = ["development-tools::testing"]
edition = "2021"
Expand All @@ -23,8 +23,12 @@ rust-version = "1.63.0" # Keep in sync with version documented in the README.md
derive_arbitrary = { version = "~1.4.0", path = "./derive", optional = true }

[features]
default = ["std"]

alloc = []
# Turn this feature on to enable support for `#[derive(Arbitrary)]`.
derive = ["derive_arbitrary"]
std = ["alloc"]

[[example]]
name = "derive_enum"
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/int_in_range.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![no_main]

use arbitrary::{unstructured::Int, Arbitrary, Result, Unstructured};
use core::{fmt::Display, ops::RangeInclusive};
use libfuzzer_sys::fuzz_target;
use std::{fmt::Display, ops::RangeInclusive};

fuzz_target!(|data: &[u8]| {
fuzz(data).expect("`int_in_range` should never return an error");
Expand Down
6 changes: 3 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{error, fmt};
use core::{error, fmt};

/// An enumeration of buffer creation errors
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -41,14 +41,14 @@ impl error::Error for Error {}
/// A `Result` with the error type fixed as `arbitrary::Error`.
///
/// Either an `Ok(T)` or `Err(arbitrary::Error)`.
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub type Result<T, E = Error> = core::result::Result<T, E>;

#[cfg(test)]
mod tests {
// Often people will import our custom `Result` type because 99.9% of
// results in a file will be `arbitrary::Result` but then have that one last
// 0.1% that want to have a custom error type. Don't make them prefix that
// 0.1% as `std::result::Result`; instead, let `arbitrary::Result` have an
// 0.1% as `core::result::Result`; instead, let `arbitrary::Result` have an
// overridable error type.
#[test]
fn can_use_custom_error_types_with_result() -> super::Result<(), String> {
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/borrow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{size_hint, Arbitrary, Result, Unstructured},
std::borrow::{Cow, ToOwned},
alloc::borrow::{Cow, ToOwned},
};

impl<'a, A> Arbitrary<'a> for Cow<'a, A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/boxed.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{size_hint, Arbitrary, Result, Unstructured},
std::boxed::Box,
alloc::{boxed::Box, string::String},
};

impl<'a, A> Arbitrary<'a> for Box<A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/collections/binary_heap.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::collections::binary_heap::BinaryHeap,
alloc::collections::binary_heap::BinaryHeap,
};

impl<'a, A> Arbitrary<'a> for BinaryHeap<A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/collections/btree_map.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::collections::btree_map::BTreeMap,
alloc::collections::btree_map::BTreeMap,
};

impl<'a, K, V> Arbitrary<'a> for BTreeMap<K, V>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/collections/btree_set.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::collections::btree_set::BTreeSet,
alloc::collections::btree_set::BTreeSet,
};

impl<'a, A> Arbitrary<'a> for BTreeSet<A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/collections/linked_list.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::collections::linked_list::LinkedList,
alloc::collections::linked_list::LinkedList,
};

impl<'a, A> Arbitrary<'a> for LinkedList<A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/collections/vec_deque.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::collections::vec_deque::VecDeque,
alloc::collections::vec_deque::VecDeque,
};

impl<'a, A> Arbitrary<'a> for VecDeque<A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/ffi/c_str.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::ffi::CString,
alloc::{ffi::CString, vec::Vec},
};

impl<'a> Arbitrary<'a> for CString {
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/rc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{size_hint, Arbitrary, Result, Unstructured},
std::rc::Rc,
alloc::rc::Rc,
};

impl<'a, A> Arbitrary<'a> for Rc<A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/string.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::string::String,
alloc::string::String,
};

impl<'a> Arbitrary<'a> for String {
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/sync.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{size_hint, Arbitrary, Result, Unstructured},
std::sync::Arc,
alloc::sync::Arc,
};

impl<'a, A> Arbitrary<'a> for Arc<A>
Expand Down
2 changes: 1 addition & 1 deletion src/foreign/alloc/vec.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::vec::Vec,
alloc::vec::Vec,
};

impl<'a, A> Arbitrary<'a> for Vec<A>
Expand Down
2 changes: 2 additions & 0 deletions src/foreign/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//!
//! [`Arbitrary`]: crate::Arbitrary

#[cfg(feature = "alloc")]
mod alloc;
mod core;
#[cfg(feature = "std")]
mod std;
6 changes: 2 additions & 4 deletions src/foreign/std/collections/hash_map.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::{
collections::hash_map::HashMap,
hash::{BuildHasher, Hash},
},
core::hash::{BuildHasher, Hash},
std::collections::hash_map::HashMap,
};

impl<'a, K, V, S> Arbitrary<'a> for HashMap<K, V, S>
Expand Down
6 changes: 2 additions & 4 deletions src/foreign/std/collections/hash_set.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use {
crate::{Arbitrary, Result, Unstructured},
std::{
collections::hash_set::HashSet,
hash::{BuildHasher, Hash},
},
core::hash::{BuildHasher, Hash},
std::collections::hash_set::HashSet,
};

impl<'a, A, S> Arbitrary<'a> for HashSet<A, S>
Expand Down
12 changes: 8 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
//! [`Arbitrary`] trait's documentation for details on
//! automatically deriving, implementing, and/or using the trait.

#![cfg_attr(not(any(feature = "std", test)), no_std)]
#![deny(bad_style)]
#![deny(missing_docs)]
#![deny(future_incompatible)]
Expand All @@ -22,6 +23,9 @@
#![deny(rust_2018_idioms)]
#![deny(unused)]

#[cfg(feature = "alloc")]
extern crate alloc;

mod error;
mod foreign;
pub mod size_hint;
Expand Down Expand Up @@ -49,7 +53,7 @@ impl core::fmt::Display for MaxRecursionReached {
}
}

impl std::error::Error for MaxRecursionReached {}
impl core::error::Error for MaxRecursionReached {}

/// Generate arbitrary structured values from raw, unstructured data.
///
Expand Down Expand Up @@ -122,9 +126,9 @@ impl std::error::Error for MaxRecursionReached {}
///
/// ```
/// # #[cfg(feature = "derive")] mod foo {
/// # pub struct MyCollection<T> { _t: std::marker::PhantomData<T> }
/// # pub struct MyCollection<T> { _t: core::marker::PhantomData<T> }
/// # impl<T> MyCollection<T> {
/// # pub fn new() -> Self { MyCollection { _t: std::marker::PhantomData } }
/// # pub fn new() -> Self { MyCollection { _t: core::marker::PhantomData } }
/// # pub fn insert(&mut self, element: T) {}
/// # }
/// use arbitrary::{Arbitrary, Result, Unstructured};
Expand Down Expand Up @@ -554,7 +558,7 @@ pub struct CompileFailTests;

// Support for `#[derive(Arbitrary)]`.
#[doc(hidden)]
#[cfg(feature = "derive")]
#[cfg(all(feature = "derive", feature = "std"))]
pub mod details {
use super::*;

Expand Down
4 changes: 2 additions & 2 deletions src/size_hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ pub fn and_all(hints: &[(usize, Option<usize>)]) -> (usize, Option<usize>) {
/// `lhs` and `rhs` size hints.
#[inline]
pub fn or(lhs: (usize, Option<usize>), rhs: (usize, Option<usize>)) -> (usize, Option<usize>) {
let lower = std::cmp::min(lhs.0, rhs.0);
let lower = core::cmp::min(lhs.0, rhs.0);
let upper = lhs
.1
.and_then(|lhs| rhs.1.map(|rhs| std::cmp::max(lhs, rhs)));
.and_then(|lhs| rhs.1.map(|rhs| core::cmp::max(lhs, rhs)));
(lower, upper)
}

Expand Down
12 changes: 11 additions & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#[cfg(feature = "alloc")]
use alloc::{rc::Rc, string::String, sync::Arc, vec::Vec};
use {
super::{Arbitrary, Result, Unstructured},
std::{collections::HashSet, fmt::Debug, hash::Hash, rc::Rc, sync::Arc},
core::{fmt::Debug, hash::Hash},
std::collections::HashSet,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're gating a chunk of these tests on the alloc feature, but then import hashset unconditionally. How does that work?

That said, I'd probably personally just specify the required features for tests in Cargo.toml and drop the cfgs. There is unlikely a future where there's any functional difference from enabling/disabling the features in this crate that would be worth testing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll gate it properly. The compiler is being smart here since HashSet is only being use in a function that is itself only used in tests that are gated behind the alloc feature, in a no_std compile time I imagine it is just dropping the import.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually doing some digging, you can import std without problem in test code because the unit test code is the only consumer of it and is compiled with std, the library code is compiled without std and linked in with the test code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured you gate the alloc feature like any other feature (like the derive feature), the tests that are testing alloc structures should be gated under the alloc feature, any code that doesn't need alloc should be tested without alloc to ensure that "version" of the library does not regress in functionality

};

/// Assert that the given expected values are all generated.
Expand Down Expand Up @@ -154,6 +157,7 @@ fn arbitrary_take_rest_for_bytes() {
}

#[test]
#[cfg(feature = "alloc")]
fn arbitrary_for_vec_u8() {
assert_generates::<Vec<u8>>([
vec![],
Expand All @@ -175,6 +179,7 @@ fn arbitrary_for_vec_u8() {
}

#[test]
#[cfg(feature = "alloc")]
fn arbitrary_for_vec_vec_u8() {
assert_generates::<Vec<Vec<u8>>>([
vec![],
Expand All @@ -193,6 +198,7 @@ fn arbitrary_for_vec_vec_u8() {
}

#[test]
#[cfg(feature = "alloc")]
fn arbitrary_for_vec_vec_vec_u8() {
assert_generates::<Vec<Vec<Vec<u8>>>>([
vec![],
Expand All @@ -217,11 +223,13 @@ fn arbitrary_for_vec_vec_vec_u8() {
}

#[test]
#[cfg(feature = "alloc")]
fn arbitrary_for_string() {
assert_generates::<String>(["".into(), "a".into(), "aa".into(), "aaa".into()]);
}

#[test]
#[cfg(feature = "alloc")]
fn arbitrary_collection() {
let x = [
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,
Expand Down Expand Up @@ -257,6 +265,7 @@ fn arbitrary_collection() {
}

#[test]
#[cfg(feature = "alloc")]
fn arbitrary_take_rest() {
// Basic examples
let x = [1, 2, 3, 4];
Expand Down Expand Up @@ -307,6 +316,7 @@ fn arbitrary_take_rest() {
}

#[test]
#[cfg(feature = "alloc")]
fn size_hint_for_tuples() {
assert_eq!(
(7, Some(7)),
Expand Down
Loading
Loading