use std::collections::BTreeMap;
use std::process::Command;
use object::{Object, ObjectSection, ObjectSymbol, SymbolKind};
mod artifact_guard;
fn synth() -> &'static str {
env!("CARGO_BIN_EXE_synth")
}
fn fixture(name: &str) -> std::path::PathBuf {
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.join("scripts/repro")
.join(name)
}
const CORPUS: &[&str] = &[
"control_step.wasm",
"flight_seam.wasm",
"flight_seam_flat.wasm",
"signed_div_const.wasm",
"i32_shift_mask_682.wat",
"gust_mix_686.wat",
"gpio_thin_846.loom.wasm",
];
const VARIANTS: &[(&str, bool)] = &[("relocatable", true), ("default", false)];
fn compile(wasm: &str, relocatable: bool, elide: Option<&str>) -> (Vec<u8>, BTreeMap<String, u64>) {
let path = fixture(wasm);
let elf = artifact_guard::unique_artifact(
&format!(
"shift_mask_elide_686_{}_{}_{}",
wasm.replace('.', "_"),
relocatable,
elide.unwrap_or("unset")
),
"o",
);
let mut cmd = Command::new(synth());
cmd.env_remove("SYNTH_SHIFT_MASK_ELIDE");
if let Some(v) = elide {
cmd.env("SYNTH_SHIFT_MASK_ELIDE", v);
}
cmd.args([
"compile",
path.to_str().unwrap(),
"-o",
elf.to_str().unwrap(),
"-b",
"arm",
"--target",
"cortex-m4",
"--all-exports",
]);
if relocatable {
cmd.arg("--relocatable");
}
let bytes = artifact_guard::compile_bytes_or_panic(
&mut cmd,
&elf,
&format!("{wasm} (relocatable={relocatable}, elide={elide:?})"),
);
let obj = object::File::parse(&*bytes).expect("parse elf");
let text = obj.section_by_name(".text").expect(".text");
let data = text.data().expect("read .text").to_vec();
let end = text.address() + data.len() as u64;
let mut starts: Vec<(u64, String)> = obj
.symbols()
.filter(|s| {
!s.name().unwrap_or("").is_empty()
&& matches!(
s.kind(),
SymbolKind::Text | SymbolKind::Label | SymbolKind::Unknown
)
&& s.address() >= text.address()
&& s.address() < end
})
.map(|s| (s.address(), s.name().unwrap().to_string()))
.collect();
starts.sort();
starts.dedup_by(|a, b| a.0 == b.0); let mut sizes = BTreeMap::new();
for (i, (addr, name)) in starts.iter().enumerate() {
let next = starts.get(i + 1).map(|(a, _)| *a).unwrap_or(end);
sizes.insert(name.clone(), next - addr);
}
(data, sizes)
}
#[test]
fn shift_mask_elide_686_default_is_on_and_optout_rolls_back() {
let mut optout_differs = false;
for &(vname, reloc) in VARIANTS {
for &wasm in CORPUS {
let (unset, _) = compile(wasm, reloc, None);
let (on, _) = compile(wasm, reloc, Some("1"));
assert_eq!(
unset, on,
"{wasm} [{vname}]: default must equal explicit ON (flag is default-on since #846)"
);
let (off, _) = compile(wasm, reloc, Some("0"));
if off != unset {
optout_differs = true;
}
}
}
assert!(
optout_differs,
"SYNTH_SHIFT_MASK_ELIDE=0 never changed bytes — the opt-out rollback is vacuous"
);
}
#[test]
fn shift_mask_elide_686_per_function_no_grow_and_gust_mix_recovers() {
for &(vname, reloc) in VARIANTS {
for &wasm in CORPUS {
let (off_bytes, off) = compile(wasm, reloc, Some("0"));
let (on_bytes, on) = compile(wasm, reloc, Some("1"));
assert_eq!(
off.keys().collect::<Vec<_>>(),
on.keys().collect::<Vec<_>>(),
"{wasm} [{vname}]: the flag must not add/drop functions"
);
for (name, off_size) in &off {
let on_size = on[name];
assert!(
on_size <= *off_size,
"{wasm} [{vname}] {name}: GREW under elision ({off_size} -> {on_size} B) \
— the pass is removal/rewrite-only, growth is a leak"
);
}
assert!(
on_bytes.len() <= off_bytes.len(),
"{wasm} [{vname}]: .text grew under elision"
);
}
}
for &(vname, reloc) in VARIANTS {
let (off_bytes, _) = compile("gust_mix_686.wat", reloc, Some("0"));
let (on_bytes, _) = compile("gust_mix_686.wat", reloc, Some("1"));
assert!(
on_bytes.len() < off_bytes.len(),
"gust_mix [{vname}]: elision must strictly shrink the constant-shift \
function ({} -> {} B)",
off_bytes.len(),
on_bytes.len()
);
}
let (off_bytes, _) = compile("i32_shift_mask_682.wat", true, Some("0"));
let (on_bytes, _) = compile("i32_shift_mask_682.wat", true, Some("1"));
assert!(
on_bytes.len() < off_bytes.len(),
"i32_shift_mask_682 [relocatable]: const >= 32 amounts must now fold mod 32 \
({} -> {} B)",
off_bytes.len(),
on_bytes.len()
);
}
fn failing_compile(out: &std::path::Path) -> Command {
let mut cmd = Command::new(synth());
cmd.args([
"compile",
"/nonexistent/rq58-flake-977-there-is-no-such-module.wat",
"-o",
out.to_str().unwrap(),
"-b",
"arm",
"--target",
"cortex-m4",
]);
cmd
}
fn good_compile(out: &std::path::Path) -> Command {
let mut cmd = Command::new(synth());
cmd.env_remove("SYNTH_SHIFT_MASK_ELIDE");
cmd.args([
"compile",
fixture("i32_shift_mask_682.wat").to_str().unwrap(),
"-o",
out.to_str().unwrap(),
"-b",
"arm",
"--target",
"cortex-m4",
"--all-exports",
"--relocatable",
]);
cmd
}
#[test]
fn artifact_guard_reports_a_failed_compile_as_a_failed_compile() {
let out = artifact_guard::unique_artifact("guard_failed_compile", "o");
let err = artifact_guard::compile_artifact(&mut failing_compile(&out), &out)
.expect_err("a compile of a nonexistent module must not yield bytes");
assert!(
err.contains("synth compile FAILED"),
"the failure must name the compile as the failure, got: {err}"
);
assert!(
err.contains("Failed to read input file"),
"the compiler's OWN stderr must travel with the failure, got: {err}"
);
assert!(
!err.contains("file magic"),
"the parser must never be the one to complain, got: {err}"
);
}
#[test]
fn artifact_guard_refuses_a_stale_artifact_instead_of_passing_on_it() {
let src = artifact_guard::unique_artifact("guard_stale_source", "o");
let good_bytes = artifact_guard::compile_artifact_or_panic(
&mut good_compile(&src),
&src,
"minting the stale artifact",
);
let _ = std::fs::remove_file(&src);
let stale = artifact_guard::unique_artifact("guard_stale_planted", "o");
std::fs::write(&stale, &good_bytes).expect("plant the stale artifact");
let planted = std::fs::read(&stale).expect("read planted");
let obj = object::File::parse(&*planted).expect("the planted artifact is a valid ELF");
assert!(
obj.section_by_name(".text").is_some(),
"the planted artifact must be substantial enough to fool an unguarded gate"
);
let err = artifact_guard::compile_artifact(&mut failing_compile(&stale), &stale)
.expect_err("REFUSAL REQUIRED: a failed compile must not return last run's bytes");
assert!(
err.contains("synth compile FAILED"),
"the refusal must name the compile failure, got: {err}"
);
assert!(
!err.contains("file magic"),
"and must not surface as a parse error, got: {err}"
);
assert!(
!std::path::Path::new(&stale).exists(),
"the stale artifact must have been removed BEFORE the compile ran — \
leaving it there is how a later reader picks up the wrong object"
);
}
#[test]
fn artifact_guard_reports_an_empty_artifact_precisely() {
let out = artifact_guard::unique_artifact("guard_empty", "o");
std::fs::write(&out, b"").expect("create empty");
let unguarded = object::File::parse(&*std::fs::read(&out).unwrap())
.expect_err("empty bytes are not an ELF");
assert!(
format!("{unguarded}").contains("Could not read file magic"),
"sanity: the historical symptom is the empty-file parse, got: {unguarded}"
);
let err = artifact_guard::read_artifact(&out).expect_err("an empty artifact must be refused");
assert!(
err.contains("EMPTY"),
"the guard must name emptiness, got: {err}"
);
let _ = std::fs::remove_file(&out);
}
#[test]
fn artifact_guard_reports_a_missing_artifact_precisely() {
let out = artifact_guard::unique_artifact("guard_missing", "o");
let err = artifact_guard::read_artifact(&out).expect_err("a missing artifact must be refused");
assert!(
err.contains("was NOT created by this invocation"),
"the guard must say the artifact is absent, got: {err}"
);
}
#[test]
fn artifact_guard_paths_are_unique_per_call() {
let a = artifact_guard::unique_artifact("shift_mask_elide_686_same_tag", "o");
let b = artifact_guard::unique_artifact("shift_mask_elide_686_same_tag", "o");
assert_ne!(
a, b,
"identical descriptions must NOT map to one path — that is #977"
);
}