Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

fuzz/tests/seeds.rs

//! **Every fuzz target takes its committed seeds without a panic, on plain stable cargo**
//! (lane OSSF-NEXT). The nightly fuzz run on the dwarves forge starts from the same
//! corpus; this test is the per-push floor under it, and it keeps the corpus current:
//! the synthetic seeds (`holger_fuzz::seeds::synthetic`) must be committed byte for byte
//! (`HOLGER_FUZZ_WRITE_SEEDS=1 cargo test` writes them).

use std::collections::BTreeSet;
use std::path::PathBuf;

fn fuzz_dir() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}

#[test]
fn every_target_is_a_bin_of_the_cargo_fuzz_layout() {
    let manifest = std::fs::read_to_string(fuzz_dir().join("Cargo.toml")).unwrap();
    assert!(
        manifest.contains("cargo-fuzz = true"),
        "the cargo-fuzz layout marks its package"
    );
    let bins: BTreeSet<String> = manifest
        .split("\n[[bin]]\n")
        .skip(1)
        .filter_map(|b| {
            b.lines()
                .find_map(|l| l.trim().strip_prefix("name = \""))
                .map(|n| n.trim_end_matches('"').to_owned())
        })
        .collect();
    let targets: BTreeSet<String> = holger_fuzz::TARGETS.iter().map(|t| t.to_string()).collect();
    assert_eq!(bins, targets, "one [[bin]] per target");
    for t in holger_fuzz::TARGETS {
        let src = std::fs::read_to_string(fuzz_dir().join(format!("fuzz_targets/{t}.rs"))).unwrap();
        assert!(
            src.contains("fuzz_target!") && src.contains(&format!("holger_fuzz::run(\"{t}\"")),
            "{t}.rs runs its own entry"
        );
    }
}

#[test]
fn the_synthetic_seeds_are_committed() {
    let write = std::env::var("HOLGER_FUZZ_WRITE_SEEDS").as_deref() == Ok("1");
    let mut stale = Vec::new();
    for (target, name, bytes) in holger_fuzz::seeds::synthetic() {
        assert!(holger_fuzz::TARGETS.contains(&target), "{target}");
        let p = fuzz_dir().join("corpus").join(target).join(&name);
        if write {
            std::fs::create_dir_all(p.parent().unwrap()).unwrap();
            std::fs::write(&p, &bytes).unwrap();
        } else if std::fs::read(&p).ok().as_deref() != Some(&bytes[..]) {
            stale.push(p.display().to_string());
        }
    }
    assert!(
        stale.is_empty(),
        "seeds not committed (HOLGER_FUZZ_WRITE_SEEDS=1 cargo test writes them):\n  {}",
        stale.join("\n  ")
    );
}

#[test]
fn every_committed_seed_runs_through_its_target() {
    for t in holger_fuzz::TARGETS {
        let dir = fuzz_dir().join("corpus").join(t);
        let mut seen = 0;
        let mut files: Vec<PathBuf> = std::fs::read_dir(&dir)
            .unwrap_or_else(|e| panic!("{}: {e}", dir.display()))
            .map(|e| e.unwrap().path())
            .collect();
        files.sort();
        for f in files {
            holger_fuzz::run(t, &std::fs::read(&f).unwrap());
            seen += 1;
        }
        assert!(seen > 0, "{t} has seeds in {}", dir.display());
    }
}

/// The edges every target must survive: nothing, one byte, a lot of one byte.
#[test]
fn every_target_survives_the_degenerate_inputs() {
    for t in holger_fuzz::TARGETS {
        for input in [&b""[..], b"\0", b"\xff", &[0u8; 4096], &[b'{'; 1024]] {
            holger_fuzz::run(t, input);
        }
    }
}