open-standards/wai/wai-pack/tests/source_alloc.rs
2026-10-05 09:04:29 -04:00

66 lines
2.6 KiB
Rust
Raw Permalink 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.

//! No field of a source sizes an allocation: a WAV `data` chunk that declares 4 GiB, and
//! a Y4M header that declares a 4096 × 4096 frame, each followed by a few bytes, are
//! refused having allocated about what they held. Its own binary: it installs a
//! counting global allocator.
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
struct Peak;
static LIVE: AtomicUsize = AtomicUsize::new(0);
static PEAK: AtomicUsize = AtomicUsize::new(0);
unsafe impl GlobalAlloc for Peak {
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
let p = unsafe { System.alloc(l) };
if !p.is_null() {
let now = LIVE.fetch_add(l.size(), Ordering::SeqCst) + l.size();
PEAK.fetch_max(now, Ordering::SeqCst);
}
p
}
unsafe fn dealloc(&self, p: *mut u8, l: Layout) {
unsafe { System.dealloc(p, l) };
LIVE.fetch_sub(l.size(), Ordering::SeqCst);
}
}
#[global_allocator]
static A: Peak = Peak;
/// The most a reader may hold beyond what it was handed, for files of a few bytes.
const BOUND: usize = 1 << 20;
fn peak_of(f: impl FnOnce() -> &'static str) -> (&'static str, usize) {
let base = LIVE.load(Ordering::SeqCst);
PEAK.store(base, Ordering::SeqCst);
let v = f();
(v, PEAK.load(Ordering::SeqCst) - base)
}
#[test]
fn a_declared_size_never_sizes_a_buffer() {
let mut wav = b"RIFF\0\0\0\0WAVEfmt \x10\0\0\0".to_vec();
wav.extend_from_slice(&[1, 0, 1, 0]); // PCM, one channel
wav.extend_from_slice(&8000u32.to_le_bytes());
wav.extend_from_slice(&16000u32.to_le_bytes());
wav.extend_from_slice(&[2, 0, 16, 0]); // align 2, 16 bits
wav.extend_from_slice(b"data");
wav.extend_from_slice(&0xffff_fffeu32.to_le_bytes());
wav.extend_from_slice(&[0; 4]);
let (v, peak) = peak_of(|| wai_pack::conformance::source_verdict("x.wav", &wav));
assert_eq!(v, "wav-truncated");
assert!(peak < BOUND, "a 4 GiB data claim allocated {peak} bytes");
// The reader's own bound, whatever block a caller asks for.
let (v, peak) = peak_of(|| {
let mut r = wai_pack::source::wav::WavReader::new(&wav[..]).unwrap();
r.next_block(u64::MAX).map(|_| "ok").unwrap_or_else(|e| e.code())
});
assert_eq!(v, "wav-truncated");
assert!(peak < BOUND, "next_block(u64::MAX) on a 4 GiB data claim allocated {peak} bytes");
let y4m = [&b"YUV4MPEG2 W4096 H4096 F25:1 C444\nFRAME\n"[..], &[16; 6]].concat();
let (v, peak) = peak_of(|| wai_pack::conformance::source_verdict("x.y4m", &y4m));
assert_eq!(v, "y4m-truncated");
assert!(peak < BOUND, "a 4096 × 4096 frame header allocated {peak} bytes");
}