diff --git a/gix-config/fuzz/Cargo.toml b/gix-config/fuzz/Cargo.toml index 554450bcc87..06762f35cea 100644 --- a/gix-config/fuzz/Cargo.toml +++ b/gix-config/fuzz/Cargo.toml @@ -13,6 +13,7 @@ cargo-fuzz = true libfuzzer-sys = "0.4.7" arbitrary = { version = "1", features = ["derive"] } bstr = "1.8.0" +anyhow = "1.0.76" [dependencies.gix-config] path = ".." diff --git a/gix-config/fuzz/fuzz_targets/fuzz_file.rs b/gix-config/fuzz/fuzz_targets/fuzz_file.rs index e219e91dcbb..e24dad2bd94 100644 --- a/gix-config/fuzz/fuzz_targets/fuzz_file.rs +++ b/gix-config/fuzz/fuzz_targets/fuzz_file.rs @@ -1,32 +1,75 @@ #![no_main] +use anyhow::Result; use arbitrary::Arbitrary; +use bstr::BStr; use gix_config::{ file::{init::Options, Metadata}, File, }; use libfuzzer_sys::fuzz_target; +use std::error::Error; +use std::fmt; use std::hint::black_box; #[derive(Arbitrary, Debug)] struct Ctx<'a> { input: &'a [u8], sections_by_name: &'a str, + section_subsection_key_triples: Vec<(&'a str, Option<&'a [u8]>, &'a str)>, } -macro_rules! unwrap_or_return { - ($e:expr) => { - match $e { - Ok(val) => val, - Err(_) => return, - } - }; -} +const DEFAULT_TRIPLE: (&str, Option<&'static [u8]>, &str) = ("section", Some(b"subsection"), "key"); -fuzz_target!(|ctx: Ctx| { +fn fuzz(ctx: Ctx) -> Result<()> { let meta = Metadata::default(); let options = Options::default(); - let file = unwrap_or_return!(File::from_bytes_no_includes(&ctx.input, meta.clone(), options.clone())); + let file = File::from_bytes_no_includes(&ctx.input, meta.clone(), options.clone())?; + + let mut triples = ctx.section_subsection_key_triples.iter(); + + let (section_name, subsection_name, key) = triples.next().unwrap_or(&DEFAULT_TRIPLE); + _ = black_box(file.string(section_name, subsection_name.map(|x| BStr::new(x)), key)); + _ = black_box(file.string_by_key(BStr::new(key))); + _ = black_box(file.string_filter(section_name, subsection_name.map(|x| BStr::new(x)), key, &mut |_| false)); + _ = black_box(file.string_filter_by_key(BStr::new(key), &mut |_| false)); + + let (section_name, subsection_name, key) = triples.next().unwrap_or(&DEFAULT_TRIPLE); + _ = black_box(file.path(section_name, subsection_name.map(|x| BStr::new(x)), key)); + _ = black_box(file.path_by_key(BStr::new(key))); + _ = black_box(file.path_filter(section_name, subsection_name.map(|x| BStr::new(x)), key, &mut |_| false)); + _ = black_box(file.path_filter_by_key(BStr::new(key), &mut |_| false)); + + let (section_name, subsection_name, key) = triples.next().unwrap_or(&DEFAULT_TRIPLE); + _ = black_box(file.boolean(section_name, subsection_name.map(|x| BStr::new(x)), key)); + _ = black_box(file.boolean_by_key(BStr::new(key))); + _ = black_box(file.boolean_filter(section_name, subsection_name.map(|x| BStr::new(x)), key, &mut |_| false)); + _ = black_box(file.boolean_filter_by_key(BStr::new(key), &mut |_| false)); + + let (section_name, subsection_name, key) = triples.next().unwrap_or(&DEFAULT_TRIPLE); + _ = black_box(file.integer(section_name, subsection_name.map(|x| BStr::new(x)), key)); + _ = black_box(file.integer_by_key(BStr::new(key))); + _ = black_box(file.integer_filter(section_name, subsection_name.map(|x| BStr::new(x)), key, &mut |_| false)); + _ = black_box(file.integer_filter_by_key(BStr::new(key), &mut |_| false)); + + let (section_name, subsection_name, key) = triples.next().unwrap_or(&DEFAULT_TRIPLE); + _ = black_box(file.strings(section_name, subsection_name.map(|x| BStr::new(x)), key)); + _ = black_box(file.strings_by_key(BStr::new(key))); + _ = black_box(file.strings_filter(section_name, subsection_name.map(|x| BStr::new(x)), key, &mut |_| false)); + _ = black_box(file.strings_filter_by_key(BStr::new(key), &mut |_| false)); + + let (section_name, subsection_name, key) = triples.next().unwrap_or(&DEFAULT_TRIPLE); + _ = black_box(file.integers(section_name, subsection_name.map(|x| BStr::new(x)), key)); + _ = black_box(file.integers_by_key(BStr::new(key))); + _ = black_box(file.integers_filter(section_name, subsection_name.map(|x| BStr::new(x)), key, &mut |_| false)); + _ = black_box(file.integers_filter_by_key(BStr::new(key), &mut |_| false)); + + let (section_name, subsection_name, key) = triples.next().unwrap_or(&DEFAULT_TRIPLE); + _ = black_box(file.integers(section_name, subsection_name.map(|x| BStr::new(x)), key)); + _ = black_box(file.integers_by_key(BStr::new(key))); + _ = black_box(file.integers_filter(section_name, subsection_name.map(|x| BStr::new(x)), key, &mut |_| false)); + _ = black_box(file.integers_filter_by_key(BStr::new(key), &mut |_| false)); + _ = black_box(file.sections().count()); _ = black_box(file.sections_and_ids().count()); _ = black_box(file.sections_and_postmatter().count()); @@ -44,9 +87,14 @@ fuzz_target!(|ctx: Ctx| { } let roundtrip_as_string: Vec = file.to_bstring().into(); - _ = unwrap_or_return!(black_box(File::from_bytes_no_includes( + _ = black_box(File::from_bytes_no_includes( &roundtrip_as_string, meta.clone(), options.clone(), - ))); + ))?; + Ok(()) +} + +fuzz_target!(|ctx: Ctx| { + _ = black_box(fuzz(ctx)); }); diff --git a/gix-config/fuzz/fuzz_targets/fuzz_file_corpus_builder.sh b/gix-config/fuzz/fuzz_targets/fuzz_file_corpus_builder.sh new file mode 100755 index 00000000000..94c65d4f8a4 --- /dev/null +++ b/gix-config/fuzz/fuzz_targets/fuzz_file_corpus_builder.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -eox pipefail + +CWD=$(pwd) + +ROOT=$1 +OUTPUT_CORPUS=$2 +FIXTURES_DIR=$(readlink -f $ROOT/gix-config/tests/fixtures) + +echo $ROOT +echo $FIXTURES_DIR +find $FIXTURES_DIR -name "*.config" -exec zip -j $OUTPUT_CORPUS {} \; + +# Generate configs. +REPO=$(mktemp -d) +cd $REPO +bash $FIXTURES_DIR/make_config_repo.sh +find . -name ".*" -exec zip $OUTPUT_CORPUS {} \; +cd $CWD +rm -r $REPO + diff --git a/gix-ref/fuzz/fuzz_targets/fuzz_log.rs b/gix-ref/fuzz/fuzz_targets/fuzz_log.rs index 54a06f5e4ef..423da5479de 100644 --- a/gix-ref/fuzz/fuzz_targets/fuzz_log.rs +++ b/gix-ref/fuzz/fuzz_targets/fuzz_log.rs @@ -1,17 +1,34 @@ #![no_main] use anyhow::Result; +use arbitrary::Arbitrary; use gix_ref::file::log; use libfuzzer_sys::fuzz_target; use std::hint::black_box; -fn fuzz(line: &[u8]) -> Result<()> { - let line = log::LineRef::from_bytes(line)?; +#[derive(Arbitrary, Debug)] +struct Ctx<'a> { + line_ref: &'a [u8], + multi_line_reverse: &'a [u8], + multi_line_forward: &'a [u8], +} + +fn fuzz(ctx: Ctx) -> Result<()> { + let line = log::LineRef::from_bytes(ctx.line_ref)?; _ = black_box(line.previous_oid()); _ = black_box(line.new_oid()); + + let mut buf = [0u8; 1024]; + let read = std::io::Cursor::new(ctx.multi_line_reverse); + let mut iter = gix_ref::file::log::iter::reverse(read, &mut buf)?; + _ = black_box(iter.map(|x| black_box(x)).count()); + + let mut iter = gix_ref::file::log::iter::forward(ctx.multi_line_forward); + _ = black_box(iter.map(|x| black_box(x)).count()); + Ok(()) } -fuzz_target!(|ctx: &[u8]| { +fuzz_target!(|ctx: Ctx| { _ = black_box(fuzz(ctx)); });