Skip to content

Commit

Permalink
Fix the allocators after discovering bad bugs in there
Browse files Browse the repository at this point in the history
  • Loading branch information
p-avital committed Jul 1, 2024
1 parent 27d304e commit 6f8d9cc
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 44 deletions.
22 changes: 4 additions & 18 deletions stabby-abi/src/alloc/allocators/libc_alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
// Pierre Avital, <[email protected]>
//

use std::io::Write;

use crate::alloc::Layout;

#[cfg(not(windows))]
Expand All @@ -31,7 +29,7 @@ unsafe fn posix_memalign(this: &mut *mut core::ffi::c_void, size: usize, align:
use libc::aligned_free;
#[cfg(not(windows))]
use libc::free as aligned_free;
use libc::{malloc, realloc};
use libc::realloc;

/// An allocator based on `libc::posix_memalign` or `libc::aligned_malloc` depending on the platform.
///
Expand Down Expand Up @@ -69,26 +67,14 @@ impl crate::alloc::IAlloc for LibcAlloc {
unsafe { aligned_free(ptr.cast()) }
}
unsafe fn realloc(&mut self, ptr: *mut (), prev: Layout, new_size: usize) -> *mut () {
dbg!(prev);
if new_size == 0 {
return core::ptr::null_mut();
}
let mut new_ptr = if prev.align <= 8 {
eprintln!(
"Previous ({ptr:?}): {:?}",
core::slice::from_raw_parts(ptr.cast::<u8>(), prev.size)
);
let new_ptr = unsafe { realloc(ptr.cast(), new_size) };
eprintln!(
"Reallocd ({new_ptr:?}): {:?}",
core::slice::from_raw_parts(new_ptr.cast::<u8>(), prev.size)
);
new_ptr
} else {
core::ptr::null_mut()
let mut new_ptr = core::ptr::null_mut::<core::ffi::c_void>();
if prev.align <= 8 {
new_ptr = unsafe { realloc(ptr.cast(), new_size) };
};
if new_ptr.is_null() {
new_ptr = core::ptr::null_mut();
let err = unsafe { posix_memalign(&mut new_ptr, prev.align, new_size) };
if err == 0 {
unsafe {
Expand Down
10 changes: 7 additions & 3 deletions stabby-abi/src/alloc/allocators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
/// This allocator is based on an ordered linked list of free memory blocks.
// pub mod freelist_alloc;

#[cfg(not(any(target_arch = "wasm32")))]
#[cfg(all(feature = "libc", not(target_arch = "wasm32")))]
/// [`IAlloc`](crate::alloc::IAlloc) bindings for `libc::malloc`
pub mod libc_alloc;
pub(crate) mod libc_alloc;
#[cfg(all(feature = "libc", not(target_arch = "wasm32")))]
pub use libc_alloc::LibcAlloc;

#[cfg(feature = "alloc-rs")]
/// Rust's GlobalAlloc, accessed through a vtable to ensure no incompatible function calls are performed
pub mod rust_alloc;
mod rust_alloc;
#[cfg(feature = "alloc-rs")]
pub use rust_alloc::RustAlloc;

#[cfg(target_arch = "wasm32")]
pub(crate) mod paging {
Expand Down
23 changes: 19 additions & 4 deletions stabby-abi/src/alloc/allocators/rust_alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,34 @@ extern "C" fn realloc(
new_size: usize,
) -> *mut () {
let prev_layout = unsafe { ptr.cast::<Layout>().sub(1).read() };
let alloc_start = unsafe { ptr.cast::<u8>().sub(prev_layout.align) };
let realloc_start = unsafe {
ptr.cast::<u8>()
.sub(prev_layout.align.max(core::mem::size_of::<Layout>()))
};
let Ok(layout) = core::alloc::Layout::from_size_align(prev_layout.size, prev_layout.align)
else {
return core::ptr::null_mut();
};
unsafe { alloc_rs::alloc::realloc(alloc_start, layout, new_size).cast() }
unsafe {
let requested = Layout::of::<Layout>().concat(Layout {
size: new_size,
align: prev_layout.align,
});
let alloc_start = alloc_rs::alloc::realloc(realloc_start, layout, requested.size);
let ret = alloc_start.add(layout.align().max(core::mem::size_of::<Layout>()));
ret.cast::<Layout>().sub(1).write(requested);
ret.cast()
}
}
extern "C" fn free(ptr: *mut ()) {
let prev_layout = unsafe { ptr.cast::<Layout>().sub(1).read() };
let alloc_start = unsafe { ptr.cast::<u8>().sub(prev_layout.align) };
let dealloc_start = unsafe {
ptr.cast::<u8>()
.sub(prev_layout.align.max(core::mem::size_of::<Layout>()))
};
unsafe {
alloc_rs::alloc::dealloc(
alloc_start,
dealloc_start,
core::alloc::Layout::from_size_align_unchecked(prev_layout.size, prev_layout.align),
)
}
Expand Down
18 changes: 9 additions & 9 deletions stabby-abi/src/alloc/collections/arc_btree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,8 +640,6 @@ fn btree_insert_libc() {
let mut vec = crate::alloc::vec::Vec::new();
let mut btree = ArcBTreeSet::new();
for _ in 0..rng.gen_range(0..800) {
eprintln!("btree: {btree:?}");
eprintln!("vec: {vec:?}");
let val = rng.gen_range(0..100u8);
if vec.binary_search(&val).is_ok() {
assert_eq!(btree.insert(val), Some(val));
Expand Down Expand Up @@ -670,20 +668,22 @@ fn btree_insert_rs() {
let mut rng = rand::thread_rng();
for i in 0..1000 {
dbg!(i);
let mut vec = crate::alloc::vec::Vec::new_in(
crate::alloc::allocators::rust_alloc::RustAlloc::default(),
);
let mut btree = ArcBTreeSet::<_, _, false, 5>::new_in(
crate::alloc::allocators::rust_alloc::RustAlloc::default(),
);
let mut vec =
crate::alloc::vec::Vec::new_in(crate::alloc::allocators::RustAlloc::default());
let mut btree =
ArcBTreeSet::<_, _, false, 5>::new_in(crate::alloc::allocators::RustAlloc::default());
for _ in 0..rng.gen_range(0..800) {
let val = rng.gen_range(0..100);
if vec.binary_search(&val).is_ok() {
assert_eq!(btree.insert(val), Some(val));
} else {
vec.push(val);
vec.sort();
assert_eq!(btree.insert(val), None);
assert_eq!(
btree.insert(val),
None,
"The BTree contained an unexpected value: {btree:?}, {vec:?}"
);
}
}
vec.sort();
Expand Down
22 changes: 12 additions & 10 deletions stabby-abi/src/alloc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ use self::vec::ptr_diff;
/// Allocators provided by `stabby`
pub mod allocators;
#[cfg(all(feature = "libc", not(any(target_arch = "wasm32"))))]
pub use allocators::libc_alloc;
/// The `libc_alloc` module, kept for API-stability.
pub mod libc_alloc {
pub use super::allocators::libc_alloc::LibcAlloc;
}

/// A generic allocation error.
#[crate::stabby]
Expand Down Expand Up @@ -49,7 +52,7 @@ pub mod vec;

/// The default allocator: libc malloc based if the libc feature is enabled, or unavailable otherwise.
#[cfg(all(feature = "libc", not(any(target_arch = "wasm32"))))]
pub type DefaultAllocator = libc_alloc::LibcAlloc;
pub type DefaultAllocator = allocators::LibcAlloc;
#[cfg(not(all(feature = "libc", not(any(target_arch = "wasm32")))))]
pub type DefaultAllocator = core::convert::Infallible;

Expand Down Expand Up @@ -358,11 +361,10 @@ impl<T, Alloc: IAlloc> AllocPtr<T, Alloc> {
),
marker: PhantomData,
};
assert!(core::ptr::eq(
debug_assert!(core::ptr::eq(
prefix.as_ptr().cast(),
this.prefix() as *const _
));
dbg!(prefix);
this
})
}
Expand All @@ -377,11 +379,10 @@ impl<T, Alloc: IAlloc> AllocPtr<T, Alloc> {
ptr: NonNull::new_unchecked(ptr.cast()),
marker: PhantomData,
};
assert!(core::ptr::eq(
debug_assert!(core::ptr::eq(
prefix.as_ptr().cast(),
this.prefix() as *const _
));
dbg!(prefix);
this
})
}
Expand All @@ -399,11 +400,13 @@ impl<T, Alloc: IAlloc> AllocPtr<T, Alloc> {
) -> Option<Self> {
let layout = Layout::of::<AllocPrefix<Alloc>>().concat(Layout::array::<T>(prev_capacity));
let ptr = alloc.realloc(
dbg!(self.prefix() as *const AllocPrefix<Alloc>)
(self.prefix() as *const AllocPrefix<Alloc>)
.cast_mut()
.cast(),
layout,
new_capacity,
Layout::of::<AllocPrefix<Alloc>>()
.concat(Layout::array::<T>(new_capacity))
.size,
);
NonNull::new(ptr).map(|prefix| unsafe {
prefix.cast::<AllocPrefix<Alloc>>().as_mut().capacity = AtomicUsize::new(new_capacity);
Expand All @@ -412,11 +415,10 @@ impl<T, Alloc: IAlloc> AllocPtr<T, Alloc> {
ptr: NonNull::new_unchecked(ptr.cast()),
marker: PhantomData,
};
assert!(core::ptr::eq(
debug_assert!(core::ptr::eq(
prefix.as_ptr().cast(),
this.prefix() as *const _
));
dbg!(prefix);
this
})
}
Expand Down

0 comments on commit 6f8d9cc

Please sign in to comment.