Ensure ArenaRef pointers are aligned to their contained type (#4002)

We think this may fix a segfault that sometimes occurs during
`display_layer`.
This commit is contained in:
Max Brunsfeld 2024-01-10 10:53:24 -08:00 committed by GitHub
commit 02ef6fc973
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -66,18 +66,19 @@ impl Arena {
}
unsafe {
let layout = alloc::Layout::new::<T>().pad_to_align();
let next_offset = self.offset.add(layout.size());
assert!(next_offset <= self.end);
let layout = alloc::Layout::new::<T>();
let offset = self.offset.add(self.offset.align_offset(layout.align()));
let next_offset = offset.add(layout.size());
assert!(next_offset <= self.end, "not enough space in Arena");
let result = ArenaBox {
ptr: self.offset.cast(),
ptr: offset.cast(),
valid: self.valid.clone(),
};
inner_writer(result.ptr, f);
self.elements.push(ArenaElement {
value: self.offset,
value: offset,
drop: drop::<T>,
});
self.offset = next_offset;
@ -199,4 +200,43 @@ mod tests {
arena.clear();
assert!(dropped.get());
}
#[test]
#[should_panic(expected = "not enough space in Arena")]
fn test_arena_overflow() {
let mut arena = Arena::new(16);
arena.alloc(|| 1u64);
arena.alloc(|| 2u64);
// This should panic.
arena.alloc(|| 3u64);
}
#[test]
fn test_arena_alignment() {
let mut arena = Arena::new(256);
let x1 = arena.alloc(|| 1u8);
let x2 = arena.alloc(|| 2u16);
let x3 = arena.alloc(|| 3u32);
let x4 = arena.alloc(|| 4u64);
let x5 = arena.alloc(|| 5u64);
assert_eq!(*x1, 1);
assert_eq!(*x2, 2);
assert_eq!(*x3, 3);
assert_eq!(*x4, 4);
assert_eq!(*x5, 5);
assert_eq!(x1.ptr.align_offset(std::mem::align_of_val(&*x1)), 0);
assert_eq!(x2.ptr.align_offset(std::mem::align_of_val(&*x2)), 0);
}
#[test]
#[should_panic(expected = "attempted to dereference an ArenaRef after its Arena was cleared")]
fn test_arena_use_after_clear() {
let mut arena = Arena::new(16);
let value = arena.alloc(|| 1u64);
arena.clear();
let _read_value = *value;
}
}