/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 | 16.2k | fn parse_and_serialize(input: &str, preserving_comments: bool) -> String { |
8 | 16.2k | let mut parser = Parser::new(input); |
9 | 16.2k | let mut serialization = String::new(); |
10 | 16.2k | let result = do_parse_and_serialize( |
11 | 16.2k | &mut parser, |
12 | 16.2k | preserving_comments, |
13 | 16.2k | TokenSerializationType::Nothing, |
14 | 16.2k | &mut serialization, |
15 | | 0, |
16 | | ); |
17 | 16.2k | if result.is_err() { |
18 | 1.17k | return String::new(); |
19 | 15.1k | } |
20 | 15.1k | serialization |
21 | 16.2k | } |
22 | | |
23 | 382k | fn do_parse_and_serialize( |
24 | 382k | input: &mut Parser, |
25 | 382k | preserving_comments: bool, |
26 | 382k | mut previous_token_type: TokenSerializationType, |
27 | 382k | serialization: &mut String, |
28 | 382k | indent_level: usize, |
29 | 382k | ) -> Result<(), ParseError<()>> { |
30 | | loop { |
31 | 92.6M | let token = if preserving_comments { |
32 | 0 | input.next_including_whitespace_and_comments() |
33 | | } else { |
34 | 92.6M | input.next_including_whitespace() |
35 | | }; |
36 | 92.6M | let token = match token { |
37 | 92.2M | Ok(token) => token, |
38 | 379k | Err(..) => break, |
39 | | }; |
40 | 92.2M | if DEBUG { |
41 | 0 | for _ in 0..indent_level { |
42 | 0 | print!(" "); |
43 | 0 | } |
44 | 0 | println!("{:?}", token); |
45 | 92.2M | } |
46 | 92.2M | if token.is_parse_error() { |
47 | 1.16k | return Err(ParseError::unexpected_token()); |
48 | 92.2M | } |
49 | 92.2M | let token_type = token.serialization_type(); |
50 | 92.2M | if previous_token_type.needs_separator_when_before(token_type) { |
51 | 87.6M | serialization.push_str("/**/"); |
52 | 87.6M | } |
53 | 92.2M | previous_token_type = token_type; |
54 | 92.2M | token.to_css(serialization).unwrap(); |
55 | 92.2M | let closing_token = match token { |
56 | 19.9k | Token::Function(_) | Token::ParenthesisBlock => Token::CloseParenthesis, |
57 | 7.45k | Token::SquareBracketBlock => Token::CloseSquareBracket, |
58 | 339k | Token::CurlyBracketBlock => Token::CloseCurlyBracket, |
59 | 91.9M | _ => continue, |
60 | | }; |
61 | | |
62 | 366k | input.parse_nested_block(|input| -> Result<_, ParseError<()>> { |
63 | 366k | do_parse_and_serialize( |
64 | 366k | input, |
65 | 366k | preserving_comments, |
66 | 366k | previous_token_type, |
67 | 366k | serialization, |
68 | 366k | indent_level + 1, |
69 | | ) |
70 | 366k | })?; |
71 | | |
72 | 364k | closing_token.to_css(serialization).unwrap(); |
73 | | } |
74 | 379k | Ok(()) |
75 | 382k | } |
76 | | |
77 | 8.13k | fn fuzz(data: &str, preserving_comments: bool) { |
78 | 8.13k | let serialization = parse_and_serialize(data, preserving_comments); |
79 | 8.13k | let reserialization = parse_and_serialize(&serialization, preserving_comments); |
80 | 8.13k | if DEBUG { |
81 | 0 | println!("IN: {:?}", serialization); |
82 | 0 | println!("OUT: {:?}", reserialization); |
83 | 8.13k | } |
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 | 8.13k | } |
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 | | }); |