crates/bindrift-fixtures/src/lib.rs
//! The fixture's AUDITED SOURCE — everything a reviewer would see in the git
//! diff. It exercises the three benign sources of binary↔source divergence the
//! BinaryDrift allowlist must NOT flag:
//!
//! - **monomorphisation**: [`transform`] compiles to one symbol per concrete `T`;
//! - **derive codegen**: `#[derive(Debug, Clone)]` on [`Widget`] emits trait-impl
//! symbols with no source body;
//! - **closures / drop glue**: [`run_clean`] closes over locals and drops values.
//!
//! The one thing NOT here is the build.rs-injected backdoor fn — its name never
//! appears in this (or any) scanned source; it lives only in the build.rs-generated
//! `$OUT_DIR/injected.rs`, pulled in by the `include!` below. That name's absence
//! from the audited tree is precisely the signal the BinaryDrift lens keys on.
/// A plain data type with derived impls (expected codegen).
#[derive(Debug, Clone)]
pub struct Widget {
pub id: u64,
pub name: String,
}
/// A generic function — the monomorphisation source. `transform::<u32>` and
/// `transform::<Widget>` are DISTINCT binary symbols that must both map back here.
#[inline(never)]
pub fn transform<T: std::fmt::Debug>(x: &T) -> String {
format!("{x:?}")
}
/// Legit code: generics, a closure, a derived `Debug`. Zero drift.
pub fn run_clean() {
let w = Widget {
id: 1,
name: "widget".to_string(),
};
let a = transform::<u32>(&7);
let b = transform::<u64>(&9);
let c = transform::<Widget>(&w);
let total: u64 = (0..4u64).map(|i| i * 2).sum(); // a closure
println!("{a} {b} {c} {total} {w:?}");
}
// The malicious codegen — a function reaching std::process::Command that appears
// ONLY in the compiled binary, never in this source file. The generated file also
// carries its own `#[used]` retention anchor, so the injected symbol survives
// dead-code elimination WITHOUT any scanned source naming it — that name's absence
// from the audited tree is the whole signal the BinaryDrift lens keys on.
include!(concat!(env!("OUT_DIR"), "/injected.rs"));