photocraft/crates/raw/tests/hostile.rs

116 lines
3.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Truncated and corrupted raw files must fail cleanly, never panic, and
//! never allocate beyond the limits.
use photocraft_raw::testgen::{Cr2Spec, DngSpec, DngStorage, mosaic, scene, tiff_ep};
use photocraft_raw::*;
fn samples() -> Vec<Vec<u8>> {
let (w, h) = (24, 12);
let cfa = mosaic(&scene(w, h), w, [0, 1, 1, 2], 64, 4000);
let mut out = Vec::new();
let mut d = DngSpec::cfa(w, h, cfa.clone());
d.bits = 12;
d.white = 4000;
d.black = vec![64];
d.as_shot_neutral = Some([0.5, 1.0, 0.7]);
d.color_matrix1 = Some((21, [3.2, -1.5, -0.5, -1.0, 1.9, 0.04, 0.06, -0.2, 1.06]));
out.push(d.build());
d.storage = DngStorage::Lj92Tiles { width: 16, height: 8 };
d.active_area = Some([1, 2, 11, 22]);
d.default_crop = Some(([1, 1], [16, 8]));
out.push(d.build());
d.storage = DngStorage::Strips { rows: 5 };
d.big_endian = true;
out.push(d.build());
let mut data = vec![600u16; 40 * 10];
for (i, v) in data.iter_mut().enumerate() {
*v = 600 + (i as u16 * 7) % 3000;
}
out.push(
Cr2Spec {
width: 40,
height: 10,
data,
precision: 14,
components: 2,
slices: vec![16, 16, 8],
borders: Some([8, 2, 39, 9]),
wb_rggb: Some([2000, 1024, 1024, 1500]),
orientation: 8,
}
.build(),
);
out.push(tiff_ep("NIKON", w, h, &cfa, [0, 1, 1, 2], 12, vec![]));
out
}
fn exercise(b: &[u8]) {
let _ = identify(b);
let _ = embedded_preview(b);
let opts = DevelopOptions { limits: Limits { max_alloc: 64 << 20, ..Limits::default() }, ..Default::default() };
if let Ok(s) = decode(b, &opts.limits) {
for m in [Demosaic::Bilinear, Demosaic::Ahd] {
let _ = develop_sensor(&s, &DevelopOptions { demosaic: m, ..opts.clone() });
}
}
}
#[test]
fn originals_develop() {
for (i, b) in samples().iter().enumerate() {
let d = develop(b, &DevelopOptions::default());
assert!(d.is_ok(), "sample {i}: {:?}", d.err());
}
}
#[test]
fn every_truncation_fails_cleanly() {
for b in samples() {
for n in (0..b.len()).step_by(3) {
exercise(&b[..n]);
}
}
}
#[test]
fn random_corruption_never_panics() {
let mut s = 0xDEAD_BEEF_u64;
let mut next = || {
s = s.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
s >> 33
};
for b in samples() {
for _ in 0..400 {
let mut c = b.clone();
for _ in 0..1 + next() % 6 {
let at = next() as usize % c.len();
c[at] = match next() % 4 {
0 => 0xFF,
1 => 0,
_ => next() as u8,
};
}
exercise(&c);
}
}
}
#[test]
fn absurd_dimensions_are_rejected_without_allocating() {
let mut d = DngSpec::cfa(4, 4, vec![0; 16]);
d.storage = DngStorage::Strips { rows: 4 };
let mut b = d.build();
// Patch the raw IFD's ImageWidth / ImageLength (LONG, inline) to 200000 × 200000.
let t = 256u16.to_le_bytes();
let mut patched = 0;
for i in 0..b.len().saturating_sub(12) {
if b[i..i + 2] == t && b[i + 2..i + 4] == 4u16.to_le_bytes() && b[i + 8..i + 12] == 4u32.to_le_bytes() {
b[i + 8..i + 12].copy_from_slice(&200_000u32.to_le_bytes());
b[i + 20..i + 24].copy_from_slice(&200_000u32.to_le_bytes());
patched += 1;
}
}
assert!(patched > 0);
assert!(matches!(decode(&b, &Limits::default()), Err(RawError::LimitExceeded(_))));
}