use netcdf_reader::NcFile;
use peak_alloc::PeakAlloc;
#[global_allocator]
static PEAK: PeakAlloc = PeakAlloc;
fn cdf1_single_record_header(numrecs: u32) -> Vec<u8> {
let mut d = Vec::new();
d.extend_from_slice(b"CDF\x01");
d.extend_from_slice(&numrecs.to_be_bytes());
d.extend_from_slice(&10u32.to_be_bytes());
d.extend_from_slice(&1u32.to_be_bytes());
d.extend_from_slice(&1u32.to_be_bytes()); d.extend_from_slice(b"t\0\0\0");
d.extend_from_slice(&0u32.to_be_bytes()); d.extend_from_slice(&0u32.to_be_bytes());
d.extend_from_slice(&0u32.to_be_bytes());
d.extend_from_slice(&11u32.to_be_bytes());
d.extend_from_slice(&1u32.to_be_bytes());
d.extend_from_slice(&1u32.to_be_bytes()); d.extend_from_slice(b"v\0\0\0");
d.extend_from_slice(&1u32.to_be_bytes()); d.extend_from_slice(&0u32.to_be_bytes()); d.extend_from_slice(&0u32.to_be_bytes()); d.extend_from_slice(&0u32.to_be_bytes());
d.extend_from_slice(&5u32.to_be_bytes()); let type_pos = d.len() - 4;
d[type_pos..type_pos + 4].copy_from_slice(&4u32.to_be_bytes());
d.extend_from_slice(&4u32.to_be_bytes()); let begin = (d.len() + 4) as u32;
d.extend_from_slice(&begin.to_be_bytes()); d
}
#[test]
fn classic_record_count_bomb_is_rejected_without_huge_allocation() {
let mut file = cdf1_single_record_header(1_000_000_000);
file.extend_from_slice(&7i32.to_be_bytes());
PEAK.reset_peak_usage();
let before = PEAK.current_usage();
let result = NcFile::from_bytes(&file);
let peak = PEAK.peak_usage().saturating_sub(before);
assert!(result.is_err(), "oversized record count should be rejected");
assert!(
peak < 4 * 1024 * 1024,
"record-count guard allocated {peak} bytes; the fix should reject before allocating",
);
}
fn cdf5_int64_attribute(nvalues: u64) -> Vec<u8> {
let mut d = Vec::new();
d.extend_from_slice(b"CDF\x05");
d.extend_from_slice(&0u64.to_be_bytes()); d.extend_from_slice(&0u32.to_be_bytes()); d.extend_from_slice(&0u64.to_be_bytes()); d.extend_from_slice(&12u32.to_be_bytes()); d.extend_from_slice(&1u64.to_be_bytes()); d.extend_from_slice(&1u64.to_be_bytes()); d.extend_from_slice(b"a\0\0\0");
d.extend_from_slice(&10u32.to_be_bytes()); d.extend_from_slice(&nvalues.to_be_bytes()); d.extend_from_slice(&1i64.to_be_bytes());
d
}
#[test]
fn classic_attribute_count_bomb_is_rejected_without_huge_allocation() {
let file = cdf5_int64_attribute(1u64 << 40);
PEAK.reset_peak_usage();
let before = PEAK.current_usage();
let result = NcFile::from_bytes(&file);
let peak = PEAK.peak_usage().saturating_sub(before);
assert!(
result.is_err(),
"oversized attribute value count should be rejected"
);
assert!(
peak < 4 * 1024 * 1024,
"attribute guard allocated {peak} bytes; the fix should reject before allocating",
);
}