#![cfg(test)]
use crate::analysis::{audit, engine, hardening, sinks};
use crate::db::Db;
use crate::listing;
use crate::model::Binary;
struct Lcg(u64);
impl Lcg {
fn next(&mut self) -> u64 {
self.0 = self
.0
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
self.0
}
fn byte(&mut self) -> u8 {
(self.next() >> 33) as u8
}
fn upto(&mut self, n: usize) -> usize {
if n == 0 {
0
} else {
(self.next() >> 33) as usize % n
}
}
}
fn exercise(bytes: &[u8]) {
let Ok(bin) = crate::formats::analyze("torture", bytes) else {
return; };
run_analyzers(&bin, bytes);
}
fn run_analyzers(bin: &Binary, bytes: &[u8]) {
let _ = hardening::run(bin);
let _ = sinks::cluster(&[]);
let an = engine::analyze(bin, bytes, 20_000, &Db::default());
let _ = sinks::find(&an);
let _ = audit::run(&an, bin, bytes);
let base = engine::display_base(bin);
let strings = listing::string_map(bin, bytes, base);
for f in an.functions.iter().take(50) {
let _ = listing::function(&an, f, &Db::default(), base, &strings);
}
for a in [bin.entry, 0, u64::MAX, bin.image_base] {
let _ = listing::data_view(bin, base, bytes, a);
}
}
#[test]
fn random_buffers_never_panic() {
let mut rng = Lcg(0x1234_5678_9abc_def0);
for _ in 0..2000 {
let len = rng.upto(512);
let buf: Vec<u8> = (0..len).map(|_| rng.byte()).collect();
exercise(&buf);
}
}
#[test]
fn tiny_buffers_never_panic() {
for len in 0..80usize {
exercise(&vec![0u8; len]);
exercise(&vec![0xffu8; len]);
}
}
#[test]
fn plausible_headers_over_garbage_never_panic() {
let magics: &[&[u8]] = &[
b"MZ",
b"\x7fELF",
&[0xfe, 0xed, 0xfa, 0xce], &[0xfe, 0xed, 0xfa, 0xcf], &[0xcf, 0xfa, 0xed, 0xfe], &[0xca, 0xfe, 0xba, 0xbe], b"!<arch>\n",
];
let mut rng = Lcg(0xdead_beef_cafe_f00d);
for m in magics {
for _ in 0..200 {
let len = rng.upto(1024);
let mut buf = m.to_vec();
buf.extend((0..len).map(|_| rng.byte()));
exercise(&buf);
}
}
}
#[test]
fn truncations_of_good_files_never_panic() {
for good in fixtures() {
for n in 0..good.len() {
exercise(&good[..n]);
}
}
}
#[test]
fn bit_flips_of_good_files_never_panic() {
let mut rng = Lcg(0x0badf00d_12345678);
for good in fixtures() {
for off in 0..good.len() {
let mut buf = good.clone();
buf[off] ^= 1 << (rng.upto(8));
exercise(&buf);
let mut big = good.clone();
big[off] = 0xff;
exercise(&big);
}
}
}
fn fixtures() -> Vec<Vec<u8>> {
use crate::formats::fixture::*;
vec![
elf_with_plt_call(),
elf_aarch64_call(),
elf_aarch64_plt_call(),
elf_with_eh_frame_hdr(),
pe_with_iat_call(),
macho_with_bind(),
]
}