Skip to content

Commit 2a5d8aa

Browse files
committed
hybrid diff
1 parent 5b9ab60 commit 2a5d8aa

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

fuzz/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ path = "fuzz_targets/ast_diff_onepass_dfa.rs"
8383
name = "ast_diff_sparse_dfa"
8484
path = "fuzz_targets/ast_diff_sparse_dfa.rs"
8585

86+
[[bin]]
87+
name = "ast_diff_hybrid"
88+
path = "fuzz_targets/ast_diff_hybrid.rs"
89+
8690
[[bin]]
8791
name = "ast_diff_nfas"
8892
path = "fuzz_targets/ast_diff_nfas.rs"

fuzz/fuzz_targets/ast_diff_hybrid.rs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#![no_main]
2+
3+
use {
4+
libfuzzer_sys::{fuzz_target, Corpus},
5+
regex_automata::{
6+
hybrid::{dfa::DFA, regex::Builder as RegexBuilder},
7+
nfa::thompson::{pikevm::PikeVM as NfaRegex, NFA},
8+
},
9+
regex_syntax::ast::Ast,
10+
};
11+
12+
#[derive(Eq, PartialEq, arbitrary::Arbitrary)]
13+
struct FuzzData {
14+
ast: Ast,
15+
haystack: String,
16+
}
17+
18+
impl std::fmt::Debug for FuzzData {
19+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20+
let mut builder = f.debug_struct("FuzzData");
21+
builder.field("ast", &format!("{}", self.ast));
22+
builder.field("haystack", &self.haystack);
23+
builder.finish()
24+
}
25+
}
26+
27+
fn do_fuzz(data: FuzzData) -> Corpus {
28+
let _ = env_logger::try_init();
29+
30+
let pattern = format!("{}", data.ast);
31+
let config = NFA::config().nfa_size_limit(Some(1 << 20));
32+
let Ok(nfa) = NFA::compiler().configure(config).build(&pattern) else {
33+
return Corpus::Reject;
34+
};
35+
let Ok(baseline) = NfaRegex::new_from_nfa(nfa) else {
36+
return Corpus::Reject;
37+
};
38+
let mut cache = baseline.create_cache();
39+
40+
let config = DFA::config().cache_capacity(1 << 20);
41+
let Ok(re) = RegexBuilder::new().dfa(config).build(&pattern) else {
42+
return Corpus::Reject;
43+
};
44+
let mut hybrid_cache = re.create_cache();
45+
46+
assert_eq!(
47+
re.is_match(&mut hybrid_cache, &data.haystack),
48+
baseline.is_match(&mut cache, &data.haystack)
49+
);
50+
let found1 = re.find(&mut hybrid_cache, &data.haystack);
51+
let found2 = baseline.find(&mut cache, &data.haystack);
52+
if let Some(found1) = found1 {
53+
let found2 = found2.expect("Found in target, but not in baseline!");
54+
assert_eq!(found1.start(), found2.start());
55+
assert_eq!(found1.end(), found2.end());
56+
}
57+
58+
// no captures
59+
60+
Corpus::Keep
61+
}
62+
63+
fuzz_target!(|data: FuzzData| -> Corpus { do_fuzz(data) });

0 commit comments

Comments
 (0)