Skip to content

Commit

Permalink
Add execute_with option
Browse files Browse the repository at this point in the history
  • Loading branch information
smoelius committed Sep 15, 2021
1 parent 605f050 commit 5742988
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ The primary effects of the `test_fuzz` macro are:

**WARNING**: Setting `enable_in_production` could introduce a denial-of-service vector. For example, setting this option for a function that is called many times with different arguments could fill up the disk. The check of [`TEST_FUZZ_WRITE`](#environment-variables) is meant to provide some defense against this possibility. Nonetheless, consider this option carefully before using it.

- **`execute_with = "function"`** - Rather than call the target directly:

- construct a closure of type `FnOnce() -> R`, where `R` is the target's return type, so that calling the closure calls the target;
- call `function` with the closure.

Calling the target in this way allows `function` to set up the call's environment. This can be useful, e.g., for fuzzing [Substrate externalities](https://substrate.dev/docs/en/knowledgebase/runtime/tests#mock-runtime-storage).

- **`no_auto_generate`** - Do not try to [auto-generate corpus files](#auto-generated-corpus-files) for the target.

- **`only_concretizations`** - Record the target's concretizations when running tests, but do not generate corpus files and do not implement a fuzzing harness. This can be useful when the target is a generic function, but it is unclear what type parameters should be used for fuzzing.
Expand Down
30 changes: 20 additions & 10 deletions macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use quote::{quote, ToTokens};
use std::{collections::BTreeMap, env::var, io::Write, str::FromStr};
use subprocess::{Exec, Redirection};
use syn::{
parse::Parser, parse_macro_input, parse_quote, punctuated::Punctuated, token, Attribute,
AttributeArgs, Block, Expr, FnArg, GenericArgument, GenericMethodArgument, GenericParam,
Generics, Ident, ImplItem, ImplItemMethod, ItemFn, ItemImpl, ItemMod, Pat, Path, PathArguments,
PathSegment, ReturnType, Signature, Stmt, Type, TypePath, TypeReference, Visibility,
WhereClause, WherePredicate,
parse::Parser, parse_macro_input, parse_quote, parse_str, punctuated::Punctuated, token,
Attribute, AttributeArgs, Block, Expr, FnArg, GenericArgument, GenericMethodArgument,
GenericParam, Generics, Ident, ImplItem, ImplItemMethod, ItemFn, ItemImpl, ItemMod, Pat, Path,
PathArguments, PathSegment, ReturnType, Signature, Stmt, Type, TypePath, TypeReference,
Visibility, WhereClause, WherePredicate,
};
use toolchain_find::find_installed_component;
use unzip_n::unzip_n;
Expand Down Expand Up @@ -166,6 +166,8 @@ struct TestFuzzOpts {
#[darling(default)]
enable_in_production: bool,
#[darling(default)]
execute_with: Option<String>,
#[darling(default)]
no_auto_generate: bool,
#[darling(default)]
only_concretizations: bool,
Expand Down Expand Up @@ -507,20 +509,28 @@ fn map_method_or_fn(
)
}
};
let call_with_deserialized_arguments = {
let call_in_environment = if let Some(s) = &opts.execute_with {
let execute_with: Expr = parse_str(s).expect("Could not parse `execute_with` argument");
parse_quote! {
#execute_with (|| #call)
}
} else {
call
};
let call_in_environment_with_deserialized_arguments = {
#[cfg(feature = "__persistent")]
quote! {
test_fuzz::afl::fuzz!(|data: &[u8]| {
let mut args = UsingReader::<_>::read_args #combined_concretization (data);
let ret: Option<<Args #combined_concretization as HasRetTy>::RetTy> = args.map(|mut args|
#call
#call_in_environment
);
});
}
#[cfg(not(feature = "__persistent"))]
quote! {
let ret: Option<<Args #combined_concretization as HasRetTy>::RetTy> = args.map(|mut args|
#call
#call_in_environment
);
}
};
Expand Down Expand Up @@ -644,13 +654,13 @@ fn map_method_or_fn(
#output_args
}
if test_fuzz::runtime::replay_enabled() {
#call_with_deserialized_arguments
#call_in_environment_with_deserialized_arguments
#output_ret
}
} else {
std::panic::set_hook(std::boxed::Box::new(|_| std::process::abort()));
#input_args
#call_with_deserialized_arguments
#call_in_environment_with_deserialized_arguments
let _ = std::panic::take_hook();
}
}
Expand Down

0 comments on commit 5742988

Please sign in to comment.