/src/gitoxide/gix-config/fuzz/fuzz_targets/fuzz_file.rs
Line | Count | Source |
1 | | #![no_main] |
2 | | |
3 | | use anyhow::Result; |
4 | | |
5 | | use bstr::{BStr, BString}; |
6 | | |
7 | | use gix_config::file::{init::Options, Metadata}; |
8 | | use libfuzzer_sys::fuzz_target; |
9 | | use std::borrow::Cow; |
10 | | use std::collections::BTreeSet; |
11 | | use std::convert::TryInto; |
12 | | use std::hint::black_box; |
13 | | use std::str; |
14 | | |
15 | 22.4k | fn fuzz_immutable_section(section: &gix_config::file::Section<'_>, buf: &mut Vec<u8>) { |
16 | 7.59M | for (key, value) in section.body().clone() { |
17 | 7.59M | let _ = black_box((key, value)); |
18 | 7.59M | } |
19 | 22.4k | let mut seen = BTreeSet::new(); |
20 | 7.59M | for key in section.value_names() { |
21 | 7.59M | if seen.insert(key) { |
22 | 44.6k | let _ = black_box(section.values(key.as_ref())); |
23 | 7.55M | } |
24 | | } |
25 | 22.4k | buf.clear(); |
26 | 22.4k | let _ = black_box(section.write_to(buf)); |
27 | 22.4k | } |
28 | | |
29 | 22.4k | fn fuzz_mutable_section( |
30 | 22.4k | file: &mut gix_config::File<'_>, |
31 | 22.4k | section_name: &str, |
32 | 22.4k | subsection_name: Option<BString>, |
33 | 22.4k | ) -> Result<()> { |
34 | | use bstr::ByteSlice; |
35 | 22.4k | let subsection_name: Option<&BStr> = subsection_name.as_ref().map(|b| (**b).as_bstr()); |
36 | | |
37 | | // Mutate section. |
38 | 22.4k | let section_id = { |
39 | 22.4k | let mut section = file.section_mut(section_name, subsection_name)?; |
40 | 22.4k | let key = section.value_names().next().cloned(); |
41 | | |
42 | 22.4k | if let Some(key) = key { |
43 | 12.4k | section.push_newline(); |
44 | 12.4k | section.set(key, BStr::new("Set value")); |
45 | 12.4k | section.push_newline(); |
46 | 12.4k | } |
47 | 22.4k | let kv_pair = section.pop().map(|(key, value)| (key.to_owned(), value)); |
48 | 22.4k | if let Some((key, value)) = kv_pair { |
49 | 12.4k | section.push_with_comment(key, Some(&value), "Popped"); |
50 | 12.4k | } else { |
51 | 9.98k | section.push("new-implicit".try_into()?, None); |
52 | 9.98k | section.push("new".try_into()?, Some("value".into())); |
53 | | } |
54 | 22.4k | section.id() |
55 | | }; |
56 | | |
57 | 22.4k | _ = black_box(file.section_mut_by_id(section_id)); |
58 | | |
59 | 22.4k | let new_section_name = section_name.to_string() + "_new"; |
60 | 22.4k | _ = black_box(file.section_mut_or_create_new(&new_section_name, subsection_name)); |
61 | | |
62 | 22.4k | if let Some(removed_section) = file.remove_section(&new_section_name, subsection_name) { |
63 | 0 | _ = black_box(file.push_section(removed_section)); |
64 | 22.4k | } |
65 | | |
66 | 22.4k | _ = black_box(file.new_section(Cow::Owned(new_section_name.clone()), None)); |
67 | 22.4k | let renamed_section_name = section_name.to_string() + "_renamed"; |
68 | 22.4k | let renamed_subsection_name: Option<Cow<'_, BStr>> = |
69 | 22.4k | subsection_name.map(|x| Cow::Owned((x.to_string() + "_renamed").into())); |
70 | 22.4k | _ = black_box(file.rename_section( |
71 | 22.4k | &new_section_name.clone(), |
72 | 22.4k | subsection_name, |
73 | 22.4k | Cow::Owned(renamed_section_name.clone()), |
74 | 22.4k | renamed_subsection_name.clone(), |
75 | 22.4k | )); |
76 | | |
77 | 22.4k | _ = black_box(file.rename_section_filter( |
78 | 22.4k | &new_section_name.clone(), |
79 | 22.4k | subsection_name, |
80 | 22.4k | Cow::Owned(renamed_section_name.clone()), |
81 | 22.4k | renamed_subsection_name.clone(), |
82 | | |_| false, |
83 | | )); |
84 | | |
85 | 22.4k | Ok(()) |
86 | 22.4k | } |
87 | | |
88 | 6.80k | fn fuzz(input: &[u8]) -> Result<()> { |
89 | 6.80k | let meta = Metadata::default(); |
90 | 6.80k | let options = Options::default(); |
91 | 6.80k | let file = gix_config::File::from_bytes_no_includes(input, meta.clone(), options)?; |
92 | | |
93 | | // Sections and frontmatter. |
94 | 6.16k | _ = black_box(file.sections_and_ids().count()); |
95 | 6.16k | _ = black_box(file.sections_and_postmatter().count()); |
96 | 6.16k | _ = black_box(file.sections_by_name("section").map(std::iter::Iterator::count)); |
97 | 6.16k | _ = black_box(file.frontmatter()); |
98 | | |
99 | 6.16k | let mut buf = Vec::new(); |
100 | 6.16k | let mut sections = Vec::new(); |
101 | | // Don't perform too much work as this can blow up the size of the file. |
102 | 22.4k | for section in file.sections().take(10) { |
103 | 22.4k | fuzz_immutable_section(section, &mut buf); |
104 | 22.4k | |
105 | 22.4k | let header = section.header(); |
106 | 22.4k | let section_name = str::from_utf8(header.name()).unwrap(); |
107 | 22.4k | let subsection_name = header.subsection_name().map(std::borrow::ToOwned::to_owned); |
108 | 22.4k | sections.push((section_name, subsection_name)); |
109 | 22.4k | } |
110 | | |
111 | 6.16k | let mut mutated_file = file.clone(); |
112 | 22.4k | for (section_name, subsection_name) in sections.into_iter() { |
113 | 22.4k | let _ = black_box(fuzz_mutable_section(&mut mutated_file, section_name, subsection_name)); |
114 | 22.4k | } |
115 | | |
116 | 6.16k | _ = black_box(mutated_file.append(file)); |
117 | 6.16k | _ = black_box(gix_config::File::from_bytes_no_includes( |
118 | 6.16k | &mutated_file.to_bstring(), |
119 | 6.16k | meta, |
120 | 6.16k | options, |
121 | 188 | )?); |
122 | | |
123 | 5.97k | Ok(()) |
124 | 6.80k | } |
125 | | |
126 | | fuzz_target!(|input: &[u8]| { |
127 | | _ = black_box(fuzz(input)); |
128 | | }); |