Skip to content

Commit 819aa03

Browse files
authored
Merge pull request #55 from HeroicKatora/master
Adds safe constructor and initialization for Heap
2 parents 4bdd8a4 + fd82f6f commit 819aa03

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

src/lib.rs

+39
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use core::alloc::GlobalAlloc;
1717
use core::alloc::Layout;
1818
#[cfg(feature = "alloc_ref")]
1919
use core::alloc::{AllocError, Allocator};
20+
use core::mem::MaybeUninit;
2021
#[cfg(feature = "use_spin")]
2122
use core::ops::Deref;
2223
use core::ptr::NonNull;
@@ -73,6 +74,32 @@ impl Heap {
7374
self.holes = HoleList::new(heap_bottom, heap_size);
7475
}
7576

77+
/// Initialize an empty heap with provided memory.
78+
///
79+
/// The caller is responsible for procuring a region of raw memory that may be utilized by the
80+
/// allocator. This might be done via any method such as (unsafely) taking a region from the
81+
/// program's memory, from a mutable static, or by allocating and leaking such memory from
82+
/// another allocator.
83+
///
84+
/// The latter method may be especially useful if the underlying allocator does not perform
85+
/// deallocation (e.g. a simple bump allocator). Then the overlaid linked-list-allocator can
86+
/// provide memory reclamation.
87+
///
88+
/// # Panics
89+
///
90+
/// This method panics if the heap is already initialized.
91+
pub fn init_from_slice(&mut self, mem: &'static mut [MaybeUninit<u8>]) {
92+
assert!(self.bottom == 0, "The heap has already been initialized.");
93+
let size = mem.len();
94+
let address = mem.as_ptr() as usize;
95+
// SAFETY: All initialization requires the bottom address to be valid, which implies it
96+
// must not be 0. Initially the address is 0. The assertion above ensures that no
97+
// initialization had been called before.
98+
// The given address and size is valid according to the safety invariants of the mutable
99+
// reference handed to us by the caller.
100+
unsafe { self.init(address, size) }
101+
}
102+
76103
/// Creates a new heap with the given `bottom` and `size`. The bottom address must be valid
77104
/// and the memory in the `[heap_bottom, heap_bottom + heap_size)` range must not be used for
78105
/// anything else. This function is unsafe because it can cause undefined behavior if the
@@ -90,6 +117,18 @@ impl Heap {
90117
}
91118
}
92119

120+
/// Creates a new heap from a slice of raw memory.
121+
///
122+
/// This has the same effect as [`init_from_slice`] on an empty heap, but it is combined into a
123+
/// single operation that can not panic.
124+
pub fn from_slice(mem: &'static mut [MaybeUninit<u8>]) -> Heap {
125+
let size = mem.len();
126+
let address = mem.as_ptr() as usize;
127+
// SAFETY: The given address and size is valid according to the safety invariants of the
128+
// mutable reference handed to us by the caller.
129+
unsafe { Self::new(address, size) }
130+
}
131+
93132
/// Allocates a chunk of the given size with the given alignment. Returns a pointer to the
94133
/// beginning of that chunk if it was successful. Else it returns `None`.
95134
/// This function scans the list of free memory blocks and uses the first block that is big

src/test.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
use super::*;
22
use core::alloc::Layout;
3-
use std::mem::{align_of, size_of};
3+
use std::mem::{align_of, size_of, MaybeUninit};
44
use std::prelude::v1::*;
55

66
fn new_heap() -> Heap {
77
const HEAP_SIZE: usize = 1000;
8-
let heap_space = Box::into_raw(Box::new([0u8; HEAP_SIZE]));
8+
let heap_space = Box::leak(Box::new([MaybeUninit::uninit(); HEAP_SIZE]));
9+
let assumed_location = heap_space.as_ptr() as usize;
910

10-
let heap = unsafe { Heap::new(heap_space as usize, HEAP_SIZE) };
11-
assert!(heap.bottom == heap_space as usize);
11+
let heap = Heap::from_slice(heap_space);
12+
assert!(heap.bottom == assumed_location);
1213
assert!(heap.size == HEAP_SIZE);
1314
heap
1415
}
1516

1617
fn new_max_heap() -> Heap {
1718
const HEAP_SIZE: usize = 1024;
1819
const HEAP_SIZE_MAX: usize = 2048;
19-
let heap_space = Box::into_raw(Box::new([0u8; HEAP_SIZE_MAX]));
20+
let heap_space = Box::leak(Box::new([MaybeUninit::<u8>::uninit(); HEAP_SIZE_MAX]));
21+
let start_ptr = heap_space.as_ptr() as usize;
2022

21-
let heap = unsafe { Heap::new(heap_space as usize, HEAP_SIZE) };
22-
assert!(heap.bottom == heap_space as usize);
23+
// Unsafe so that we have provenance over the whole allocation.
24+
let heap = unsafe { Heap::new(start_ptr, HEAP_SIZE) };
25+
assert!(heap.bottom == start_ptr);
2326
assert!(heap.size == HEAP_SIZE);
2427
heap
2528
}

0 commit comments

Comments
 (0)