use apache_avro::Codec;
use apache_avro::error::Details;
const BUDGET: usize = 1024; const BOMB_PLAINTEXT: usize = 8 * 1024;
fn set_budget() {
apache_avro::util::max_allocation_bytes(BUDGET);
}
fn assert_bounded(codec: Codec) {
set_budget();
let mut bomb = vec![0u8; BOMB_PLAINTEXT];
codec.compress(&mut bomb).expect("compress bomb");
assert!(
bomb.len() <= BUDGET,
"compressed bomb ({} bytes) should be far smaller than the budget",
bomb.len()
);
let result = codec.decompress(&mut bomb);
match result {
Err(e) => assert!(
matches!(e.details(), Details::MemoryAllocation { .. }),
"expected a MemoryAllocation error, got {e:?}"
),
Ok(()) => panic!("a decompressed output exceeding the budget must be rejected"),
}
let original = b"apache avro decompression within budget".to_vec();
let mut data = original.clone();
codec.compress(&mut data).expect("compress small");
codec.decompress(&mut data).expect("decompress small");
assert_eq!(data, original);
}
#[test]
fn deflate_decompression_is_bounded() {
use apache_avro::DeflateSettings;
assert_bounded(Codec::Deflate(DeflateSettings::default()));
}
#[test]
#[cfg(feature = "snappy")]
fn snappy_decompression_is_bounded() {
assert_bounded(Codec::Snappy);
}
#[test]
#[cfg(feature = "zstandard")]
fn zstandard_decompression_is_bounded() {
use apache_avro::ZstandardSettings;
assert_bounded(Codec::Zstandard(ZstandardSettings::default()));
}
#[test]
#[cfg(feature = "bzip")]
fn bzip2_decompression_is_bounded() {
use apache_avro::Bzip2Settings;
assert_bounded(Codec::Bzip2(Bzip2Settings::default()));
}
#[test]
#[cfg(feature = "xz")]
fn xz_decompression_is_bounded() {
use apache_avro::XzSettings;
assert_bounded(Codec::Xz(XzSettings::default()));
}