Perform a bounds check when allocating in the arena (#3735)
This ensures we don't invoke undefined behavior when overflowing. Release Notes: - N/A
This commit is contained in:
commit
57a372fcdc
1 changed files with 30 additions and 23 deletions
|
@ -2,13 +2,13 @@ use std::{
|
|||
alloc,
|
||||
cell::Cell,
|
||||
ops::{Deref, DerefMut},
|
||||
ptr::{self, NonNull},
|
||||
ptr,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
struct ArenaElement {
|
||||
value: NonNull<u8>,
|
||||
drop: unsafe fn(NonNull<u8>),
|
||||
value: *mut u8,
|
||||
drop: unsafe fn(*mut u8),
|
||||
}
|
||||
|
||||
impl Drop for ArenaElement {
|
||||
|
@ -21,8 +21,9 @@ impl Drop for ArenaElement {
|
|||
}
|
||||
|
||||
pub struct Arena {
|
||||
start: NonNull<u8>,
|
||||
offset: usize,
|
||||
start: *mut u8,
|
||||
end: *mut u8,
|
||||
offset: *mut u8,
|
||||
elements: Vec<ArenaElement>,
|
||||
valid: Rc<Cell<bool>>,
|
||||
}
|
||||
|
@ -31,10 +32,12 @@ impl Arena {
|
|||
pub fn new(size_in_bytes: usize) -> Self {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align(size_in_bytes, 1).unwrap();
|
||||
let ptr = alloc::alloc(layout);
|
||||
let start = alloc::alloc(layout);
|
||||
let end = start.add(size_in_bytes);
|
||||
Self {
|
||||
start: NonNull::new_unchecked(ptr),
|
||||
offset: 0,
|
||||
start,
|
||||
end,
|
||||
offset: start,
|
||||
elements: Vec::new(),
|
||||
valid: Rc::new(Cell::new(true)),
|
||||
}
|
||||
|
@ -45,7 +48,7 @@ impl Arena {
|
|||
self.valid.set(false);
|
||||
self.valid = Rc::new(Cell::new(true));
|
||||
self.elements.clear();
|
||||
self.offset = 0;
|
||||
self.offset = self.start;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -58,24 +61,28 @@ impl Arena {
|
|||
ptr::write(ptr, f());
|
||||
}
|
||||
|
||||
unsafe fn drop<T>(ptr: NonNull<u8>) {
|
||||
std::ptr::drop_in_place(ptr.cast::<T>().as_ptr());
|
||||
unsafe fn drop<T>(ptr: *mut u8) {
|
||||
std::ptr::drop_in_place(ptr.cast::<T>());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let layout = alloc::Layout::new::<T>().pad_to_align();
|
||||
let ptr = NonNull::new_unchecked(self.start.as_ptr().add(self.offset).cast::<T>());
|
||||
inner_writer(ptr.as_ptr(), f);
|
||||
let next_offset = self.offset.add(layout.size());
|
||||
assert!(next_offset <= self.end);
|
||||
|
||||
let result = ArenaRef {
|
||||
ptr: self.offset.cast(),
|
||||
valid: self.valid.clone(),
|
||||
};
|
||||
|
||||
inner_writer(result.ptr, f);
|
||||
self.elements.push(ArenaElement {
|
||||
value: ptr.cast(),
|
||||
value: self.offset,
|
||||
drop: drop::<T>,
|
||||
});
|
||||
self.offset += layout.size();
|
||||
ArenaRef {
|
||||
ptr,
|
||||
valid: self.valid.clone(),
|
||||
}
|
||||
self.offset = next_offset;
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +94,7 @@ impl Drop for Arena {
|
|||
}
|
||||
|
||||
pub struct ArenaRef<T: ?Sized> {
|
||||
ptr: NonNull<T>,
|
||||
ptr: *mut T,
|
||||
valid: Rc<Cell<bool>>,
|
||||
}
|
||||
|
||||
|
@ -104,7 +111,7 @@ impl<T: ?Sized> ArenaRef<T> {
|
|||
#[inline(always)]
|
||||
pub fn map<U: ?Sized>(mut self, f: impl FnOnce(&mut T) -> &mut U) -> ArenaRef<U> {
|
||||
ArenaRef {
|
||||
ptr: unsafe { NonNull::new_unchecked(f(&mut *self)) },
|
||||
ptr: f(&mut self),
|
||||
valid: self.valid,
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +130,7 @@ impl<T: ?Sized> Deref for ArenaRef<T> {
|
|||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.validate();
|
||||
unsafe { self.ptr.as_ref() }
|
||||
unsafe { &*self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,7 +138,7 @@ impl<T: ?Sized> DerefMut for ArenaRef<T> {
|
|||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.validate();
|
||||
unsafe { self.ptr.as_mut() }
|
||||
unsafe { &mut *self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue