diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..a092511 --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,3 @@ +target +corpus +artifacts diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000..643ff1a --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,121 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "norm" +version = "0.1.0" +dependencies = [ + "memchr", +] + +[[package]] +name = "norm-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "norm", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..3824e13 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "norm-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +norm = { path = "..", features = ["fzf-v1", "fzf-v2"] } +libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] } + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "fzf" +path = "fuzz_targets/fzf.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/fzf.rs b/fuzz/fuzz_targets/fzf.rs new file mode 100644 index 0000000..666fbf1 --- /dev/null +++ b/fuzz/fuzz_targets/fzf.rs @@ -0,0 +1,67 @@ +#![no_main] + +use libfuzzer_sys::arbitrary::{self, Arbitrary}; +use libfuzzer_sys::fuzz_target; +use norm::fzf::{FzfParser, FzfScheme, FzfV1, FzfV2}; +use norm::{CaseSensitivity, Metric}; + +#[derive(Arbitrary, Copy, Clone, Debug)] +struct Query<'a>(&'a str); + +#[derive(Arbitrary, Clone, Debug)] +struct Candidate<'a>(&'a str); + +fn with_opts(mut fun: F) +where + F: FnMut(CaseSensitivity, bool, FzfScheme), +{ + for case_sensitivity in [ + CaseSensitivity::Sensitive, + CaseSensitivity::Insensitive, + CaseSensitivity::Smart, + ] { + for normalization in [true, false] { + for scheme in + [FzfScheme::Default, FzfScheme::Path, FzfScheme::History] + { + fun(case_sensitivity, normalization, scheme) + } + } + } +} + +fuzz_target!(|data: (Query, Candidate)| { + let (Query(query), Candidate(candidate)) = data; + + let mut parser = FzfParser::new(); + + let query = parser.parse(query); + + let mut fzf_v1 = FzfV1::new(); + + let mut fzf_v2 = FzfV2::new(); + + with_opts(|case_sensitivity, normalization, scheme| { + fzf_v1 = core::mem::take(&mut fzf_v1) + .with_case_sensitivity(case_sensitivity) + .with_normalization(normalization) + .with_scoring_scheme(scheme); + + if let Some(mach) = fzf_v1.distance(query, candidate) { + for range in mach.matched_ranges() { + let _s = &candidate[range.clone()]; + } + } + + fzf_v2 = core::mem::take(&mut fzf_v2) + .with_case_sensitivity(case_sensitivity) + .with_normalization(normalization) + .with_scoring_scheme(scheme); + + if let Some(mach) = fzf_v2.distance(query, candidate) { + for range in mach.matched_ranges() { + let _s = &candidate[range.clone()]; + } + } + }); +});