in bindings/rust/extended/s2n-tls/src/fingerprint.rs [583:672]
fn raw_may_allocate_memory() -> Result<(), Box<dyn Error>> {
let client_hello = ClientHello::parse_client_hello(CLIENT_HELLO_BYTES)?;
let mut builder = Fingerprint::builder(FingerprintType::JA3)?;
let minimum_size = JA3_FULL_STRING.len();
let large_size = minimum_size + 100;
// If we want to allocate the known value of the raw string,
// then that allocation must happen when raw() is called rather than
// when the fingerprint is built.
let snapshot = checkers::with(|| {
let mut fingerprint = builder.build(&client_hello).unwrap();
// Calculating the hash is necessary to calculate the raw_size,
// But the hash_does_not_allocate_memory test proves this does not
// allocate any memory.
fingerprint.hash().unwrap();
fingerprint.raw().unwrap();
});
// Expect a single allocation to allocate the raw string
assert_eq!(snapshot.events.allocs(), 1);
assert_eq!(snapshot.events.reallocs(), 0);
assert_eq!(snapshot.events.frees(), 0);
assert_eq!(snapshot.events.max_memory_used().unwrap(), minimum_size);
// Snapshots must be cumulative to accurately track total allocations,
// so keep track of the current snapshot.
let mut full_snapshot = snapshot;
// Expect that repeating either the build or the calculation does not
// lead to any new allocations.
let snapshot = checkers::with(|| {
for _ in 0..10 {
let mut fingerprint = builder.build(&client_hello).unwrap();
// Calculating the hash is necessary to calculate the raw_size,
// But the hash_does_not_allocate_memory test proves this does not
// allocate any memory.
fingerprint.hash().unwrap();
for _ in 0..10 {
fingerprint.raw().unwrap();
}
}
});
assert!(snapshot.events.is_empty());
// If we set a larger raw size on the builder,
// then the raw string is reallocated.
let snapshot = checkers::with(|| {
builder.set_raw_size(large_size).unwrap();
});
assert_eq!(snapshot.events.allocs(), 0);
assert_eq!(snapshot.events.reallocs(), 1);
assert_eq!(snapshot.events.frees(), 0);
// Snapshots must be cumulative to accurately track total allocations,
// so add the new snapshot events.
for event in snapshot.events.as_slice() {
full_snapshot.events.push(event.clone());
}
// The new total memory should be the larger size we set on the builder.
assert_eq!(full_snapshot.events.max_memory_used().unwrap(), large_size);
// If the raw size was set on the builder, then the raw string is not
// allocated when raw() is called.
let snapshot = checkers::with(|| {
let mut fingerprint = builder.build(&client_hello).unwrap();
fingerprint.raw().unwrap();
});
assert!(snapshot.events.is_empty());
// If we set a smaller raw size on the builder,
// then the raw string is not reallocated.
let snapshot = checkers::with(|| {
builder.set_raw_size(minimum_size).unwrap();
});
assert!(snapshot.events.is_empty());
// Recalculating the raw string does not reallocate the raw string
let snapshot = checkers::with(|| {
for _ in 0..10 {
let mut fingerprint = builder.build(&client_hello).unwrap();
fingerprint.raw().unwrap();
}
});
assert!(snapshot.events.is_empty());
Ok(())
}