/src/rust-cssparser/fuzz/fuzz_targets/cssparser.rs
Line | Count | Source |
1 | | #![no_main] |
2 | | |
3 | | use cssparser::*; |
4 | | |
5 | | const DEBUG: bool = false; |
6 | | |
7 | 15.9k | fn parse_and_serialize(input: &str, preserving_comments: bool) -> String { |
8 | 15.9k | let mut parser = Parser::new(input); |
9 | 15.9k | let mut serialization = String::new(); |
10 | 15.9k | let result = do_parse_and_serialize( |
11 | 15.9k | &mut parser, |
12 | 15.9k | preserving_comments, |
13 | 15.9k | TokenSerializationType::Nothing, |
14 | 15.9k | &mut serialization, |
15 | | 0, |
16 | | ); |
17 | 15.9k | if result.is_err() { |
18 | 1.11k | return String::new(); |
19 | 14.8k | } |
20 | 14.8k | serialization |
21 | 15.9k | } |
22 | | |
23 | 372k | fn do_parse_and_serialize( |
24 | 372k | input: &mut Parser, |
25 | 372k | preserving_comments: bool, |
26 | 372k | mut previous_token_type: TokenSerializationType, |
27 | 372k | serialization: &mut String, |
28 | 372k | indent_level: usize, |
29 | 372k | ) -> Result<(), ParseError<()>> { |
30 | | loop { |
31 | 85.9M | let token = if preserving_comments { |
32 | 0 | input.next_including_whitespace_and_comments() |
33 | | } else { |
34 | 85.9M | input.next_including_whitespace() |
35 | | }; |
36 | 85.9M | let token = match token { |
37 | 85.6M | Ok(token) => token, |
38 | 368k | Err(..) => break, |
39 | | }; |
40 | 85.6M | if DEBUG { |
41 | 0 | for _ in 0..indent_level { |
42 | 0 | print!(" "); |
43 | 0 | } |
44 | 0 | println!("{:?}", token); |
45 | 85.6M | } |
46 | 85.6M | if token.is_parse_error() { |
47 | 1.10k | return Err(ParseError::unexpected_token()); |
48 | 85.6M | } |
49 | 85.6M | let token_type = token.serialization_type(); |
50 | 85.6M | if previous_token_type.needs_separator_when_before(token_type) { |
51 | 81.6M | serialization.push_str("/**/"); |
52 | 81.6M | } |
53 | 85.6M | previous_token_type = token_type; |
54 | 85.6M | token.to_css(serialization).unwrap(); |
55 | 85.6M | let closing_token = match token { |
56 | 18.6k | Token::Function(_) | Token::ParenthesisBlock => Token::CloseParenthesis, |
57 | 7.52k | Token::SquareBracketBlock => Token::CloseSquareBracket, |
58 | 330k | Token::CurlyBracketBlock => Token::CloseCurlyBracket, |
59 | 85.2M | _ => continue, |
60 | | }; |
61 | | |
62 | 356k | input.parse_nested_block(|input| -> Result<_, ParseError<()>> { |
63 | 356k | do_parse_and_serialize( |
64 | 356k | input, |
65 | 356k | preserving_comments, |
66 | 356k | previous_token_type, |
67 | 356k | serialization, |
68 | 356k | indent_level + 1, |
69 | | ) |
70 | 356k | })?; |
71 | | |
72 | 353k | closing_token.to_css(serialization).unwrap(); |
73 | | } |
74 | 368k | Ok(()) |
75 | 372k | } |
76 | | |
77 | 7.96k | fn fuzz(data: &str, preserving_comments: bool) { |
78 | 7.96k | let serialization = parse_and_serialize(data, preserving_comments); |
79 | 7.96k | let reserialization = parse_and_serialize(&serialization, preserving_comments); |
80 | 7.96k | if DEBUG { |
81 | 0 | println!("IN: {:?}", serialization); |
82 | 0 | println!("OUT: {:?}", reserialization); |
83 | 7.96k | } |
84 | | // TODO: This should ideally pass, but it doesn't for numbers near our |
85 | | // precision limits, so parsing e.g., 9999995e-45 generates a serialization |
86 | | // of 10e-39 because of dtoa rounding, and parsing _that_ generates a |
87 | | // serialization of 1e-38. |
88 | | // |
89 | | // assert_eq!( |
90 | | // serialization, reserialization, |
91 | | // "Serialization should be idempotent" |
92 | | // ); |
93 | 7.96k | } |
94 | | |
95 | | libfuzzer_sys::fuzz_target!(|data: &str| { |
96 | | fuzz(data, false); |
97 | | // TODO(emilio): Serialization when preserving comments is not idempotent. |
98 | | // But in browsers we never preserve comments so that's ok... |
99 | | // fuzz(data, true); |
100 | | }); |