From d068a337ba4e2900140bd810383764019bacee3f Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Thu, 4 May 2023 15:21:05 +0100 Subject: [PATCH] Fuzz options, and make failure print out a test --- fuzz/Cargo.toml | 2 +- fuzz/fuzz_targets/fuzz_regex_match.rs | 81 +++++++++++++++++++++------ 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index c1e2776348..453b308699 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" cargo-fuzz = true [dependencies] -libfuzzer-sys = "0.4.1" +libfuzzer-sys = { version = "0.4.1", features = ["arbitrary-derive"] } [dependencies.regex] path = ".." diff --git a/fuzz/fuzz_targets/fuzz_regex_match.rs b/fuzz/fuzz_targets/fuzz_regex_match.rs index bd9eefad54..7a66b16544 100644 --- a/fuzz/fuzz_targets/fuzz_regex_match.rs +++ b/fuzz/fuzz_targets/fuzz_regex_match.rs @@ -1,22 +1,71 @@ #![no_main] use libfuzzer_sys::fuzz_target; -fuzz_target!(|data: &[u8]| { - if data.len() < 2 { - return; +use libfuzzer_sys::arbitrary; + +#[derive(arbitrary::Arbitrary)] +struct FuzzCase<'a> { + pattern: &'a str, + input: &'a str, + case_insensitive: bool, + multi_line: bool, + dot_matches_new_line: bool, + swap_greed: bool, + ignore_whitespace: bool, + unicode: bool, + octal: bool, +} + +impl std::fmt::Debug for FuzzCase<'_> { + fn fmt( + &self, + fmt: &mut std::fmt::Formatter, + ) -> Result<(), std::fmt::Error> { + let Self { + pattern, + case_insensitive, + multi_line, + dot_matches_new_line, + swap_greed, + ignore_whitespace, + unicode, + octal, + input, + } = self; + + write!( + fmt, + r#" +let r = regex::RegexBuilder::new({pattern:?}) + .case_insensitive({case_insensitive:?}) + .multi_line({multi_line:?}) + .dot_matches_new_line({dot_matches_new_line:?}) + .swap_greed({swap_greed:?}) + .ignore_whitespace({ignore_whitespace:?}) + .unicode({unicode:?}) + .octal({octal:?}) + .build(); + +if let Ok(re) = r {{ + re.is_match({input:?}); +}} + "# + ) } - let split_point = data[0] as usize; - if let Ok(data) = std::str::from_utf8(&data[1..]) { - use std::cmp::max; - // split data into regular expression and actual input to search through - let len = data.chars().count(); - let split_off_point = max(split_point, 1) % len as usize; - let char_index = data.char_indices().nth(split_off_point); - if let Some((char_index, _)) = char_index { - let (pattern, input) = data.split_at(char_index); - if let Ok(re) = regex::Regex::new(pattern) { - re.is_match(input); - } - } +} + +fuzz_target!(|case: FuzzCase| { + let r = regex::RegexBuilder::new(case.pattern) + .case_insensitive(case.case_insensitive) + .multi_line(case.multi_line) + .dot_matches_new_line(case.dot_matches_new_line) + .swap_greed(case.swap_greed) + .ignore_whitespace(case.ignore_whitespace) + .unicode(case.unicode) + .octal(case.octal) + .build(); + + if let Ok(re) = r { + re.is_match(case.input); } });