Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework features #284

Merged
merged 1 commit into from
Oct 5, 2023
Merged
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
2 changes: 1 addition & 1 deletion cargo-test-fuzz/src/bin/cargo_test_fuzz/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ mod tests {
#[allow(clippy::unwrap_used)]
cargo_test_fuzz(&[
"--features",
&("test-fuzz/".to_owned() + test_fuzz::serde_format().as_feature()),
&("test-fuzz/".to_owned() + test_fuzz::serde_format::as_feature()),
"--no-run",
"--no-instrumentation",
"target",
Expand Down
15 changes: 8 additions & 7 deletions cargo-test-fuzz/tests/fuzz_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ const TIMEOUT: &str = "60";
fn fuzz_foo_qwerty() {
// smoelius: When `bincode` is enabled, `cargo-afl` fails because "the program crashed with one
// of the test cases provided."
// smoelius: `to_string` is used here because `SerdeFormat` won't necessarily contain the
// `Bincode` variant.
if serde_format().to_string() == "Bincode" {
fuzz("test_foo_qwerty", 2);
} else {
fuzz("test_foo_qwerty", 1);
};
fuzz(
"test_foo_qwerty",
if serde_format::serializes_variant_names() {
1
} else {
2
},
);
}

#[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))]
Expand Down
1 change: 0 additions & 1 deletion docs/crates.dot
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ digraph {
"cargo-test-fuzz" -> "internal"
"cargo-test-fuzz" -> "test-fuzz"
"cargo-test-fuzz" -> "testing"
"macro" -> "internal"
"macro-generated-code" -> "test-fuzz"
"runtime" -> "internal"
"test-fuzz" -> "internal"
Expand Down
19 changes: 14 additions & 5 deletions internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@ authors = ["Samuel E. Moelius III <sam@moeli.us>"]
license = "AGPL-3.0 WITH mif-exception"
repository = "https://github.com/trailofbits/test-fuzz"

# smoelius: https://github.com/rust-lang/cargo/issues/1839
# Because of the above issue, the crate for the default format (bincode) must be included regardless
# of whether it is selected. A test-fuzz test (`link`) verifies that the crate's code is not linked
# in when another format is selected.

[dependencies]
cargo_metadata = "0.18"
proc-macro2 = "1.0"
quote = "1.0"
serde = "1.0"
strum_macros = "0.25"

bincode = "1.3"
cbor4ii = { version = "0.3", features = ["serde1", "use_std"], optional = true }
serde_cbor = { version = "0.11", optional = true }

[features]
__auto_concretize = []
__serde_bincode = []
__serde_cbor = []
__serde_cbor4ii = []
__serde_cbor = ["serde_cbor"]
__serde_cbor4ii = ["cbor4ii"]

[package.metadata.cargo-udeps.ignore]
normal = ["bincode"]
3 changes: 1 addition & 2 deletions internal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ pub use auto_concretize::enabled as auto_concretize_enabled;

pub mod dirs;

mod serde_format;
pub use serde_format::*;
pub mod serde_format;
105 changes: 68 additions & 37 deletions internal/src/serde_format.rs
Original file line number Diff line number Diff line change
@@ -1,56 +1,87 @@
#![allow(clippy::use_self)]
use serde::{de::DeserializeOwned, Serialize};
use std::io::Read;

use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens, TokenStreamExt};
use strum_macros::Display;

#[derive(Copy, Clone, Debug, Display, Eq, PartialEq)]
pub enum SerdeFormat {
#[cfg(any(serde_default, feature = "__serde_bincode"))]
Bincode,
#[cfg(feature = "__serde_cbor")]
Cbor,
#[cfg(feature = "__serde_cbor4ii")]
Cbor4ii,
}
#[cfg(any(serde_default, feature = "__serde_bincode"))]
const BYTE_LIMIT: u64 = 1024 * 1024 * 1024;

#[allow(clippy::vec_init_then_push)]
#[must_use]
pub fn serde_format() -> SerdeFormat {
pub fn as_feature() -> &'static str {
let mut formats = vec![];

#[cfg(any(serde_default, feature = "__serde_bincode"))]
formats.push(SerdeFormat::Bincode);
formats.push("serde_bincode");

#[cfg(feature = "__serde_cbor")]
formats.push(SerdeFormat::Cbor);
formats.push("serde_cbor");

#[cfg(feature = "__serde_cbor4ii")]
formats.push(SerdeFormat::Cbor4ii);
formats.push("serde_cbor4ii");

assert!(
formats.len() <= 1,
"{}",
"Multiple serde formats selected: {formats:?}"
);

formats.pop().expect("No serde format selected")
}

impl SerdeFormat {
#[must_use]
pub fn as_feature(self) -> &'static str {
match self {
#[cfg(any(serde_default, feature = "__serde_bincode"))]
Self::Bincode => "serde_bincode",
#[cfg(feature = "__serde_cbor")]
Self::Cbor => "serde_cbor",
#[cfg(feature = "__serde_cbor4ii")]
Self::Cbor4ii => "serde_cbor4ii",
}
}
#[must_use]
pub fn serializes_variant_names() -> bool {
#[cfg(any(serde_default, feature = "__serde_bincode"))]
return false;

#[cfg(feature = "__serde_cbor")]
return true;

#[cfg(feature = "__serde_cbor4ii")]
return true;
}

pub fn serialize<T: Serialize>(args: &T) -> Vec<u8> {
#[cfg(any(serde_default, feature = "__serde_bincode"))]
return {
use bincode::Options;
// smoelius: From
// https://github.com/bincode-org/bincode/blob/c44b5e364e7084cdbabf9f94b63a3c7f32b8fb68/src/lib.rs#L102-L103 :
// /// **Warning:** the default configuration used by [`bincode::serialize`] is not
// /// the same as that used by the `DefaultOptions` struct. ...
// The point is that `bincode::serialize(..)` and `bincode::options().serialize(..)` use
// different encodings, even though the latter uses "default" options.
bincode::options()
.with_limit(BYTE_LIMIT)
.serialize(args)
.unwrap()
};

#[cfg(feature = "__serde_cbor")]
return serde_cbor::to_vec(args).unwrap();

#[cfg(feature = "__serde_cbor4ii")]
return {
let mut data = Vec::new();
cbor4ii::serde::to_writer(&mut data, args).unwrap();
data
};
}

impl ToTokens for SerdeFormat {
fn to_tokens(&self, tokens: &mut TokenStream) {
let ident = Ident::new(&self.to_string(), Span::call_site());
tokens.append_all(quote! {
test_fuzz::SerdeFormat::#ident
});
}
pub fn deserialize<T: DeserializeOwned, R: Read>(reader: R) -> Option<T> {
#[cfg(any(serde_default, feature = "__serde_bincode"))]
return {
use bincode::Options;
bincode::options()
.with_limit(BYTE_LIMIT)
.deserialize_from(reader)
.ok()
};

#[cfg(feature = "__serde_cbor")]
return serde_cbor::from_reader(reader).ok();

#[cfg(feature = "__serde_cbor4ii")]
return {
let reader = std::io::BufReader::new(reader);
cbor4ii::serde::from_reader(reader).ok()
};
}
7 changes: 2 additions & 5 deletions macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ subprocess = "0.2"
syn = { version = "2.0", features = ["full", "parsing", "visit", "visit-mut"] }
toolchain_find = "0.4"

internal = { path = "../internal", package = "test-fuzz-internal", version = "=4.0.1" }
internal = { path = "../internal", package = "test-fuzz-internal", version = "=4.0.1", optional = true }

[features]
__auto_concretize = []
__auto_concretize = ["internal"]
__persistent = []
__serde_bincode = ["internal/__serde_bincode"]
__serde_cbor = ["internal/__serde_cbor"]
__serde_cbor4ii = ["internal/__serde_cbor4ii"]
8 changes: 0 additions & 8 deletions macro/build.rs

This file was deleted.

6 changes: 2 additions & 4 deletions macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#![cfg_attr(feature = "__auto_concretize", feature(proc_macro_span))]

use darling::{ast::NestedMeta, FromMeta};
use internal::serde_format;
use itertools::MultiUnzip;
use once_cell::sync::Lazy;
use proc_macro::TokenStream;
Expand Down Expand Up @@ -453,7 +452,6 @@ fn map_method_or_fn(
)
};

let serde_format = serde_format();
let write_concretizations = quote! {
let impl_concretization = [
#(#impl_ty_names),*
Expand Down Expand Up @@ -628,7 +626,7 @@ fn map_method_or_fn(
let args = Args(
#(#args_is),*
);
test_fuzz::runtime::write_args(#serde_format, &args);
test_fuzz::runtime::write_args(&args);
}

struct UsingReader<R>(R);
Expand All @@ -639,7 +637,7 @@ fn map_method_or_fn(
struct Args #ty_generics (
#(#pub_arg_tys),*
) #args_where_clause;
let args = test_fuzz::runtime::read_args::<Args #ty_generics_as_turbofish, _>(#serde_format, reader);
let args = test_fuzz::runtime::read_args::<Args #ty_generics_as_turbofish, _>(reader);
args.map(|args| #mod_ident :: Args(
#(#args_is),*
))
Expand Down
16 changes: 0 additions & 16 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,10 @@ authors = ["Samuel E. Moelius III <sam@moeli.us>"]
license = "AGPL-3.0 WITH mif-exception"
repository = "https://github.com/trailofbits/test-fuzz"

# smoelius: https://github.com/rust-lang/cargo/issues/1839
# Because of the above issue, the crate for the default format (bincode) must be included regardless
# of whether it is selected. A test-fuzz test (`link`) verifies that the crate's code is not linked
# in when another format is selected.

[dependencies]
bincode = "1.3"
cbor4ii = { version = "0.3", features = ["serde1", "use_std"], optional = true }
hex = "0.4"
num-traits = "0.2"
serde = { version = "1.0", features = ["derive"] }
serde_cbor = { version = "0.11", optional = true }
sha-1 = "0.10"

internal = { path = "../internal", package = "test-fuzz-internal", version = "=4.0.1" }

[features]
__serde_bincode = []
__serde_cbor = ["serde_cbor"]
__serde_cbor4ii = ["cbor4ii"]

[package.metadata.cargo-udeps.ignore]
normal = ["bincode"]
8 changes: 0 additions & 8 deletions runtime/build.rs

This file was deleted.

53 changes: 5 additions & 48 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use internal::{
concretizations_directory_from_args_type, corpus_directory_from_args_type,
impl_concretizations_directory_from_args_type,
},
SerdeFormat,
serde_format,
};
use serde::{de::DeserializeOwned, Serialize};
use sha1::{Digest, Sha1};
Expand All @@ -21,9 +21,6 @@ pub use num_traits;

pub mod traits;

#[cfg(any(serde_default, feature = "__serde_bincode"))]
const BYTE_LIMIT: u64 = 1024 * 1024 * 1024;

// smoelius: TryDebug, etc. use Nikolai Vazquez's trick from `impls`.
// https://github.com/nvzqz/impls#how-it-works

Expand Down Expand Up @@ -160,33 +157,9 @@ pub fn write_concretization<T>(args: &[&str]) {
write_data(&concretizations, data.as_bytes()).unwrap();
}

#[allow(unused_variables)]
pub fn write_args<T: Serialize>(serde_format: SerdeFormat, args: &T) {
pub fn write_args<T: Serialize>(args: &T) {
let corpus = corpus_directory_from_args_type::<T>();
let data = match serde_format {
#[cfg(any(serde_default, feature = "__serde_bincode"))]
SerdeFormat::Bincode => {
use bincode::Options;
// smoelius: From
// https://github.com/bincode-org/bincode/blob/c44b5e364e7084cdbabf9f94b63a3c7f32b8fb68/src/lib.rs#L102-L103 :
// /// **Warning:** the default configuration used by [`bincode::serialize`] is not
// /// the same as that used by the `DefaultOptions` struct. ...
// The point is that `bincode::serialize(..)` and `bincode::options().serialize(..)` use
// different encodings, even though the latter uses "default" options.
bincode::options()
.with_limit(BYTE_LIMIT)
.serialize(args)
.unwrap()
}
#[cfg(feature = "__serde_cbor")]
SerdeFormat::Cbor => serde_cbor::to_vec(args).unwrap(),
#[cfg(feature = "__serde_cbor4ii")]
SerdeFormat::Cbor4ii => {
let mut data = Vec::new();
cbor4ii::serde::to_writer(&mut data, args).unwrap();
data
}
};
let data = serde_format::serialize(args);
write_data(&corpus, &data).unwrap();
}

Expand All @@ -200,22 +173,6 @@ pub fn write_data(dir: &Path, data: &[u8]) -> io::Result<()> {
write(path_buf, data)
}

pub fn read_args<T: DeserializeOwned, R: Read>(serde_format: SerdeFormat, reader: R) -> Option<T> {
match serde_format {
#[cfg(any(serde_default, feature = "__serde_bincode"))]
SerdeFormat::Bincode => {
use bincode::Options;
bincode::options()
.with_limit(BYTE_LIMIT)
.deserialize_from(reader)
.ok()
}
#[cfg(feature = "__serde_cbor")]
SerdeFormat::Cbor => serde_cbor::from_reader(reader).ok(),
#[cfg(feature = "__serde_cbor4ii")]
SerdeFormat::Cbor4ii => {
let reader = std::io::BufReader::new(reader);
cbor4ii::serde::from_reader(reader).ok()
}
}
pub fn read_args<T: DeserializeOwned, R: Read>(reader: R) -> Option<T> {
serde_format::deserialize(reader)
}
6 changes: 0 additions & 6 deletions test-fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,12 @@ auto_concretize = [
]
serde_bincode = [
"internal/__serde_bincode",
"runtime/__serde_bincode",
"test-fuzz-macro/__serde_bincode",
]
serde_cbor = [
"internal/__serde_cbor",
"runtime/__serde_cbor",
"test-fuzz-macro/__serde_cbor",
]
serde_cbor4ii = [
"internal/__serde_cbor4ii",
"runtime/__serde_cbor4ii",
"test-fuzz-macro/__serde_cbor4ii",
]
__persistent = ["afl", "test-fuzz-macro/__persistent"]

Expand Down
Loading