Skip to content

Commit

Permalink
Merge pull request #55 from HeroicKatora/master
Browse files Browse the repository at this point in the history
Adds safe constructor and initialization for Heap
  • Loading branch information
phil-opp committed Oct 17, 2021
2 parents 4bdd8a4 + fd82f6f commit 819aa03
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 7 deletions.
39 changes: 39 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use core::alloc::GlobalAlloc;
use core::alloc::Layout;
#[cfg(feature = "alloc_ref")]
use core::alloc::{AllocError, Allocator};
use core::mem::MaybeUninit;
#[cfg(feature = "use_spin")]
use core::ops::Deref;
use core::ptr::NonNull;
Expand Down Expand Up @@ -73,6 +74,32 @@ impl Heap {
self.holes = HoleList::new(heap_bottom, heap_size);
}

/// Initialize an empty heap with provided memory.
///
/// The caller is responsible for procuring a region of raw memory that may be utilized by the
/// allocator. This might be done via any method such as (unsafely) taking a region from the
/// program's memory, from a mutable static, or by allocating and leaking such memory from
/// another allocator.
///
/// The latter method may be especially useful if the underlying allocator does not perform
/// deallocation (e.g. a simple bump allocator). Then the overlaid linked-list-allocator can
/// provide memory reclamation.
///
/// # Panics
///
/// This method panics if the heap is already initialized.
pub fn init_from_slice(&mut self, mem: &'static mut [MaybeUninit<u8>]) {
assert!(self.bottom == 0, "The heap has already been initialized.");
let size = mem.len();
let address = mem.as_ptr() as usize;
// SAFETY: All initialization requires the bottom address to be valid, which implies it
// must not be 0. Initially the address is 0. The assertion above ensures that no
// initialization had been called before.
// The given address and size is valid according to the safety invariants of the mutable
// reference handed to us by the caller.
unsafe { self.init(address, size) }
}

/// Creates a new heap with the given `bottom` and `size`. The bottom address must be valid
/// and the memory in the `[heap_bottom, heap_bottom + heap_size)` range must not be used for
/// anything else. This function is unsafe because it can cause undefined behavior if the
Expand All @@ -90,6 +117,18 @@ impl Heap {
}
}

/// Creates a new heap from a slice of raw memory.
///
/// This has the same effect as [`init_from_slice`] on an empty heap, but it is combined into a
/// single operation that can not panic.
pub fn from_slice(mem: &'static mut [MaybeUninit<u8>]) -> Heap {
let size = mem.len();
let address = mem.as_ptr() as usize;
// SAFETY: The given address and size is valid according to the safety invariants of the
// mutable reference handed to us by the caller.
unsafe { Self::new(address, size) }
}

/// Allocates a chunk of the given size with the given alignment. Returns a pointer to the
/// beginning of that chunk if it was successful. Else it returns `None`.
/// This function scans the list of free memory blocks and uses the first block that is big
Expand Down
17 changes: 10 additions & 7 deletions src/test.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
use super::*;
use core::alloc::Layout;
use std::mem::{align_of, size_of};
use std::mem::{align_of, size_of, MaybeUninit};
use std::prelude::v1::*;

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

let heap = unsafe { Heap::new(heap_space as usize, HEAP_SIZE) };
assert!(heap.bottom == heap_space as usize);
let heap = Heap::from_slice(heap_space);
assert!(heap.bottom == assumed_location);
assert!(heap.size == HEAP_SIZE);
heap
}

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

let heap = unsafe { Heap::new(heap_space as usize, HEAP_SIZE) };
assert!(heap.bottom == heap_space as usize);
// Unsafe so that we have provenance over the whole allocation.
let heap = unsafe { Heap::new(start_ptr, HEAP_SIZE) };
assert!(heap.bottom == start_ptr);
assert!(heap.size == HEAP_SIZE);
heap
}
Expand Down

0 comments on commit 819aa03

Please sign in to comment.