Skip to content

Commit 8cd91da

Browse files
authored
Merge pull request #2 from george-lim/fix-alignment
Fix misaligned pointer dereference
2 parents 5c2d952 + e583518 commit 8cd91da

File tree

5 files changed

+119
-41
lines changed

5 files changed

+119
-41
lines changed

Cargo.lock

Lines changed: 99 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ordered-pool-allocator"
3-
version = "0.1.0"
3+
version = "0.1.1"
44
authors = ["George Lim <lim.george@me.com>"]
55
edition = "2021"
66
description = "A fast and compact pool allocator with block sorting support."
@@ -10,7 +10,7 @@ keywords = ["allocator", "memory-pool"]
1010
categories = ["data-structures", "memory-management"]
1111

1212
[dev-dependencies]
13-
rand = "0.8"
13+
rand = "0.9"
1414

1515
[profile.test]
1616
opt-level = 3

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024 George Lim
3+
Copyright (c) 2025 George Lim
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ In order to achieve the fastest time complexity for block allocation and dealloc
2626

2727
### Memory Layout
2828

29-
![memory-layout](https://github.com/george-lim/ordered-pool-allocator/assets/21700768/24c78c1d-e0d4-48ce-9d0d-963fb45dde9b)
29+
![memory-layout](https://github.com/user-attachments/assets/994064e0-f7ae-44ea-ab9b-1973fdff7985)

src/lib.rs

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,10 @@ use std::{
88
};
99

1010
/// An allocator for `T` objects, with a block index of `N` bytes.
11-
///
12-
/// If `N` is 1, then `blocks_capacity` will be `u8::MAX`.
13-
/// If `N` is 2, then `blocks_capacity` will be `u16::MAX`.
1411
pub struct OrderedPoolAllocator<'buf, T, const N: usize = { mem::size_of::<usize>() }> {
12+
physical_blocks_ptr: *mut MaybeUninit<T>,
1513
physical_block_indices_ptr: *mut [u8; N],
1614
virtual_block_indices_ptr: *mut [u8; N],
17-
physical_blocks_ptr: *mut MaybeUninit<T>,
1815
blocks_len: usize,
1916
deallocated_blocks_len: usize,
2017
blocks_capacity: usize,
@@ -25,18 +22,21 @@ impl<'buf, T, const N: usize> OrderedPoolAllocator<'buf, T, N> {
2522
pub fn new_in(buf: &'buf mut [u8]) -> Self {
2623
let blocks_capacity = usize::MAX
2724
.min(2usize.pow(8).pow(N as u32) - 1)
28-
.min(buf.len() / (2 * mem::size_of::<[u8; N]>() + mem::size_of::<MaybeUninit<T>>()));
25+
.min(buf.len() / (mem::size_of::<MaybeUninit<T>>() + 2 * mem::size_of::<[u8; N]>()));
2926

3027
unsafe {
3128
Self {
32-
physical_block_indices_ptr: buf.as_mut_ptr().cast(),
33-
virtual_block_indices_ptr: buf
29+
physical_blocks_ptr: buf.as_mut_ptr().cast(),
30+
physical_block_indices_ptr: buf
3431
.as_mut_ptr()
35-
.add(blocks_capacity * mem::size_of::<[u8; N]>())
32+
.add(blocks_capacity * mem::size_of::<MaybeUninit<T>>())
3633
.cast(),
37-
physical_blocks_ptr: buf
34+
virtual_block_indices_ptr: buf
3835
.as_mut_ptr()
39-
.add(2 * blocks_capacity * mem::size_of::<[u8; N]>())
36+
.add(
37+
blocks_capacity
38+
* (mem::size_of::<MaybeUninit<T>>() + mem::size_of::<[u8; N]>()),
39+
)
4040
.cast(),
4141
blocks_len: 0,
4242
deallocated_blocks_len: 0,
@@ -48,12 +48,12 @@ impl<'buf, T, const N: usize> OrderedPoolAllocator<'buf, T, N> {
4848

4949
/// Allocates a block and returns a pointer to the block.
5050
///
51-
/// This method will always prioritize reallocating an existing deallocated block over allocating
52-
/// a new block.
51+
/// This method will always prioritize reallocating an existing deallocated block over allocating a new block.
5352
///
5453
/// # Safety
5554
///
56-
/// Behavior is undefined if the returned pointer points to an uninitialized instance of `T` when the allocator is dropped.
55+
/// Behavior is undefined if the returned pointer points to an uninitialized instance of `T` when the allocator is
56+
/// dropped.
5757
pub unsafe fn allocate(&mut self) -> Result<NonNull<T>, AllocError> {
5858
let physical_block_index = match self.deallocated_blocks_len {
5959
0 if self.is_full() => return Err(AllocError),
@@ -96,7 +96,6 @@ impl<'buf, T, const N: usize> OrderedPoolAllocator<'buf, T, N> {
9696
/// Behavior is undefined if any of the following conditions are violated:
9797
///
9898
/// * `ptr` must point to an instance of `T` allocated by this allocator.
99-
///
10099
/// * `ptr` must not point to an instance of `T` that has already been dropped or deallocated by this allocator.
101100
pub unsafe fn deallocate(&mut self, ptr: NonNull<T>) {
102101
if self.is_empty() {
@@ -206,10 +205,6 @@ impl<'buf, T, const N: usize> OrderedPoolAllocator<'buf, T, N> {
206205
}
207206

208207
fn usize_to_bytes(block_index: usize) -> [u8; N] {
209-
if N == mem::size_of::<usize>() {
210-
unsafe { return *block_index.to_le_bytes().as_ptr().cast() }
211-
}
212-
213208
let mut buf = [0u8; N];
214209

215210
unsafe {
@@ -327,7 +322,7 @@ mod tests {
327322
}
328323

329324
unsafe fn deallocate(sut: &mut OrderedPoolAllocator<SecureU32, 1>, rng: &mut ThreadRng) {
330-
let i = rng.gen_range(0..sut.len());
325+
let i = rng.random_range(0..sut.len());
331326
let ptr = NonNull::new_unchecked(sut[i].as_mut_ptr());
332327
sut.deallocate(ptr);
333328
assert_eq!(0, ptr.as_ref().0)
@@ -336,14 +331,14 @@ mod tests {
336331
unsafe {
337332
let mut buf = [0u8; 128];
338333
let mut sut = OrderedPoolAllocator::<SecureU32, 1>::new_in(&mut buf);
339-
let mut rng = rand::thread_rng();
334+
let mut rng = rand::rng();
340335

341336
for _ in 0..20_000_000 {
342337
if sut.is_empty() {
343338
allocate(&mut sut, u32::MAX)
344339
} else if sut.is_full() {
345340
deallocate(&mut sut, &mut rng)
346-
} else if rng.gen_bool(0.5) {
341+
} else if rng.random_bool(0.5) {
347342
allocate(&mut sut, u32::MAX)
348343
} else {
349344
deallocate(&mut sut, &mut rng)

0 commit comments

Comments
 (0)