Coverage Report

Created: 2025-07-23 07:16

/src/regex/fuzz/fuzz_targets/ast_roundtrip.rs
Line
Count
Source (jump to first uncovered line)
1
#![no_main]
2
3
use {
4
    libfuzzer_sys::{fuzz_target, Corpus},
5
    regex_syntax::ast::{
6
        parse::Parser, visit, Ast, Flag, Flags, GroupKind, Visitor,
7
    },
8
};
9
10
31.5k
#[derive(Eq, PartialEq, arbitrary::Arbitrary)]
Unexecuted instantiation: <ast_roundtrip::FuzzData as arbitrary::Arbitrary>::arbitrary::{closure#0}
Unexecuted instantiation: <ast_roundtrip::FuzzData as arbitrary::Arbitrary>::arbitrary::{closure#1}
Unexecuted instantiation: <ast_roundtrip::FuzzData as arbitrary::Arbitrary>::arbitrary::{closure#2}
Unexecuted instantiation: <ast_roundtrip::FuzzData as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#0}
Unexecuted instantiation: <ast_roundtrip::FuzzData as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#2}
<ast_roundtrip::FuzzData as arbitrary::Arbitrary>::arbitrary_take_rest::{closure#1}
Line
Count
Source
10
10.5k
#[derive(Eq, PartialEq, arbitrary::Arbitrary)]
<ast_roundtrip::FuzzData as arbitrary::Arbitrary>::try_size_hint::{closure#0}
Line
Count
Source
10
20.9k
#[derive(Eq, PartialEq, arbitrary::Arbitrary)]
11
struct FuzzData {
12
    ast: Ast,
13
}
14
15
impl std::fmt::Debug for FuzzData {
16
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17
0
        let mut builder = f.debug_struct("FuzzData");
18
0
        builder.field("ast", &self.ast);
19
0
        builder.field("stringified", &format!("{}", self.ast));
20
0
        builder.finish()
21
0
    }
22
}
23
24
struct VerboseVisitor;
25
26
impl Visitor for VerboseVisitor {
27
    type Output = ();
28
    type Err = ();
29
30
5.06k
    fn finish(self) -> Result<Self::Output, Self::Err> {
31
5.06k
        Ok(())
32
5.06k
    }
33
34
170k
    fn visit_pre(&mut self, ast: &Ast) -> Result<Self::Output, Self::Err> {
35
170k
        let reject_flags = |flags: &Flags| {
36
3.38k
            flags.flag_state(Flag::IgnoreWhitespace).unwrap_or(false)
37
3.38k
        };
38
1.80k
        match ast {
39
1.80k
            Ast::Flags(x) if reject_flags(&x.flags) => return Err(()),
40
5.52k
            Ast::Group(x) => match x.kind {
41
1.57k
                GroupKind::NonCapturing(ref flags) if reject_flags(flags) => {
42
169
                    return Err(())
43
                }
44
5.35k
                _ => Ok(()),
45
            },
46
164k
            _ => Ok(()),
47
        }
48
170k
    }
49
}
50
51
fuzz_target!(|data: FuzzData| -> Corpus {
52
    let _ = env_logger::try_init();
53
54
    let pattern = format!("{}", data.ast);
55
    let Ok(ast) = Parser::new().parse(&pattern) else {
56
        return Corpus::Keep;
57
    };
58
    if visit(&ast, VerboseVisitor).is_err() {
59
        return Corpus::Reject;
60
    }
61
    let ast2 = Parser::new().parse(&ast.to_string()).unwrap();
62
    assert_eq!(
63
        ast,
64
        ast2,
65
        "Found difference:\
66
         \nleft:  {:?}\
67
         \nright: {:?}\
68
         \nIf these two match, then there was a parsing difference; \
69
           maybe non-determinism?",
70
        ast.to_string(),
71
        ast2.to_string()
72
    );
73
    Corpus::Keep
74
});