plugins/native/znippy-plugin-git/fuzz/fuzz_targets/read_paths.rs
//! Every Arrow IPC read path of znippy-plugin-git, on bytes from nowhere: each
//! must end in Ok or Err (or a clean, shorter read for a log), never a panic,
//! an abort or an OOM. The first byte picks the path, the rest is its input.
#![no_main]
use std::sync::OnceLock;
use libfuzzer_sys::fuzz_target;
use znippy_common::arrow::buffer::{Buffer, MutableBuffer};
use znippy_plugin_git::GitObjectKind;
use znippy_plugin_git::exploded_arrow::{ExplodePolicy, ExplodedArchive};
use znippy_plugin_git::index_layout::{ObjectIndex, OneTableFourColumns};
fn scratch(name: &str) -> std::path::PathBuf {
static D: OnceLock<std::path::PathBuf> = OnceLock::new();
D.get_or_init(|| {
let d = std::env::temp_dir().join(format!("plugin-git-fuzz-{}", std::process::id()));
std::fs::create_dir_all(&d).unwrap();
d
})
.join(name)
}
fuzz_target!(|data: &[u8]| {
let Some((&sel, b)) = data.split_first() else {
return;
};
match sel % 6 {
0 => {
let _ = znippy_plugin_git::decode_graph(b);
}
1 => {
let _ = znippy_plugin_git::decode_reach(b);
}
2 => {
let _ = znippy_plugin_git::scan_frames(b);
}
3 => {
let p = scratch("journal");
std::fs::write(&p, b).unwrap();
let _ = znippy_plugin_git::archive_write::read_journal(&p);
}
4 => {
let p = scratch("exploded.arrow");
std::fs::write(&p, b).unwrap();
if let Ok(t) = ExplodedArchive::open_with_policy(&p, ExplodePolicy::Full) {
let _ = t.rows();
for n in [1u8, 2, 9] {
let _ = t.content(&[n; 20]);
let _ = t.name(&[n; 20]);
}
let _ = t.of_kind(GitObjectKind::Blob);
}
}
_ => {
let mut mb = MutableBuffer::with_capacity(b.len());
mb.extend_from_slice(b);
let buf: Buffer = mb.into();
let _ = OneTableFourColumns::from_persisted(buf);
}
}
});