Skip to content

Commit

Permalink
Add option to automatically apply cast_checks
Browse files Browse the repository at this point in the history
  • Loading branch information
smoelius committed May 3, 2024
1 parent 8b65ab4 commit cf6075c
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,10 @@ test-fuzz = { version = "*", features = ["self_ty_in_mod_name"] }

The `test-fuzz` package currently supports the following features:

### `cast_checks`

Use [`cast_checks`] to automatically check target functions for invalid casts.

### `self_ty_in_mod_name`

Incorporate an `impl`'s `Self` type into the names of modules generated for the `impl`. Expansion of the `test_fuzz` macro adds a module definition to the enclosing scope. By default, the module is named `target_fuzz`, where `target` is the name of the target. If the target appears in an `impl` block, then use of this feature causes the module to instead be named `path_target_fuzz`, where `path` is the path of the `impl`'s `Self` type converted to snake case and joined with `_`. (See also [`rename`] above.)
Expand Down Expand Up @@ -521,6 +525,7 @@ These options are incompatible in the following sense. If a fuzz target's argume
[`cargo test-fuzz` command]: #cargo-test-fuzz-command
[`cargo test-fuzz`]: #cargo-test-fuzz-command
[`cargo-clone`]: https://github.com/JanLikar/cargo-clone
[`cast_checks`]: https://github.com/trailofbits/cast_checks
[`convert`]: #convert--x-y
[`core::ops::Add`]: https://doc.rust-lang.org/beta/core/ops/trait.Add.html
[`core::ops::Div`]: https://doc.rust-lang.org/beta/core/ops/trait.Div.html
Expand Down
35 changes: 35 additions & 0 deletions cargo-test-fuzz/tests/fuzz_cast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use predicates::prelude::*;
use testing::{examples, retry, CommandExt};

const MAX_TOTAL_TIME: &str = "60";

#[test]
fn fuzz_cast() {
examples::test("cast", "test")
.unwrap()
.logged_assert()
.success();

for use_cast_checks in [false, true] {
let mut args = vec![
"--exit-code",
"--run-until-crash",
"--max-total-time",
MAX_TOTAL_TIME,
];
let code = if use_cast_checks {
args.push("--features=test-fuzz/cast_checks");
1
} else {
0
};
retry(3, || {
examples::test_fuzz("cast", "target")
.unwrap()
.args(&args)
.logged_assert()
.try_code(predicate::eq(code))
})
.unwrap();
}
}
9 changes: 9 additions & 0 deletions examples/tests/cast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[test_fuzz::test_fuzz]
fn target(x: u64) {
let _ = x as u32;
}

#[test]
fn test() {
target(0);
}
1 change: 1 addition & 0 deletions macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ quote = "1.0"
syn = { version = "2.0", features = ["full", "parsing", "visit", "visit-mut"] }

[features]
__cast_checks = []
__persistent = []
__self_ty_in_mod_name = ["heck"]

Expand Down
14 changes: 14 additions & 0 deletions macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,18 @@ fn map_method_or_fn(
}
}

let mut attrs = attrs.clone();
let maybe_use_cast_checks = if cfg!(feature = "__cast_checks") {
attrs.push(parse_quote! {
#[test_fuzz::cast_checks::enable]
});
quote! {
use test_fuzz::cast_checks;
}
} else {
quote! {}
};

let impl_ty_idents = type_idents(generics);
let ty_idents = type_idents(&sig.generics);
let combined_type_idents = [impl_ty_idents.clone(), ty_idents.clone()].concat();
Expand Down Expand Up @@ -724,6 +736,8 @@ fn map_method_or_fn(
(
parse_quote! {
#(#attrs)* #vis #defaultness #sig {
#maybe_use_cast_checks

#write_generic_args_and_args

#in_production_write_generic_args_and_args
Expand Down
2 changes: 2 additions & 0 deletions test-fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository = "https://github.com/trailofbits/test-fuzz"

[dependencies]
afl = { version = "0.15", optional = true }
cast_checks = { version = "0.1", optional = true }
serde = "1.0"

internal = { path = "../internal", package = "test-fuzz-internal", version = "=5.0.0" }
Expand All @@ -34,6 +35,7 @@ testing = { path = "../testing", package = "test-fuzz-testing" }
# https://github.com/djkoloski/rust_serialization_benchmark

[features]
cast_checks = ["dep:cast_checks", "test-fuzz-macro/__cast_checks"]
self_ty_in_mod_name = ["test-fuzz-macro/__self_ty_in_mod_name"]
serde_bincode = ["internal/__serde_bincode"]
serde_cbor = ["internal/__serde_cbor"]
Expand Down
4 changes: 4 additions & 0 deletions test-fuzz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ pub use test_fuzz_macro::{test_fuzz, test_fuzz_impl};
#[cfg(feature = "__persistent")]
pub use afl;

// smoelius: Do the same for `cast_checks`.
#[cfg(feature = "cast_checks")]
pub use cast_checks;

// smoelius: Unfortunately, the same trick doesn't work for serde.
// https://github.com/serde-rs/serde/issues/1465

Expand Down

0 comments on commit cf6075c

Please sign in to comment.