Skip to content

Commit c2aa6ec

Browse files
authored
Merge pull request rust-osdev#75 from rust-osdev/fix-74
Address unleaking of heap data causing miri test failures
2 parents f7c2d8e + 14bf9c5 commit c2aa6ec

File tree

1 file changed

+72
-44
lines changed

1 file changed

+72
-44
lines changed

src/test.rs

+72-44
Original file line numberDiff line numberDiff line change
@@ -10,80 +10,107 @@ use std::{
1010

1111
#[repr(align(128))]
1212
struct Chonk<const N: usize> {
13-
data: [MaybeUninit<u8>; N],
13+
data: MaybeUninit<[u8; N]>,
1414
}
1515

1616
impl<const N: usize> Chonk<N> {
17-
pub fn new() -> Self {
18-
Self {
19-
data: [MaybeUninit::uninit(); N],
20-
}
17+
/// Returns (almost certainly aliasing) pointers to the Chonk
18+
/// as well as the data payload.
19+
///
20+
/// MUST be freed with a matching call to `Chonk::unleak`
21+
pub fn new() -> (*mut Chonk<N>, *mut u8) {
22+
let heap_space_ptr: *mut Chonk<N> = {
23+
let owned_box = Box::new(Self {
24+
data: MaybeUninit::uninit(),
25+
});
26+
let mutref = Box::leak(owned_box);
27+
mutref
28+
};
29+
let data_ptr: *mut u8 = unsafe { core::ptr::addr_of_mut!((*heap_space_ptr).data).cast() };
30+
(heap_space_ptr, data_ptr)
31+
}
32+
33+
pub unsafe fn unleak(putter: *mut Chonk<N>) {
34+
drop(Box::from_raw(putter))
2135
}
2236
}
2337

24-
pub struct OwnedHeap<F> {
38+
pub struct Dropper<const N: usize> {
39+
putter: *mut Chonk<N>,
40+
}
41+
42+
impl<const N: usize> Dropper<N> {
43+
fn new(putter: *mut Chonk<N>) -> Self {
44+
Self { putter }
45+
}
46+
}
47+
48+
impl<const N: usize> Drop for Dropper<N> {
49+
fn drop(&mut self) {
50+
unsafe { Chonk::unleak(self.putter) }
51+
}
52+
}
53+
54+
pub struct OwnedHeap<const N: usize> {
2555
heap: Heap,
26-
_drop: F,
56+
// /!\ SAFETY /!\: Load bearing drop order! `_drop` MUST be dropped AFTER
57+
// `heap` is dropped. This is enforced by rust's built-in drop ordering, as
58+
// long as `_drop` is declared after `heap`.
59+
_drop: Dropper<N>,
2760
}
2861

29-
impl<F> Deref for OwnedHeap<F> {
62+
impl<const N: usize> Deref for OwnedHeap<N> {
3063
type Target = Heap;
3164

3265
fn deref(&self) -> &Self::Target {
3366
&self.heap
3467
}
3568
}
3669

37-
impl<F> DerefMut for OwnedHeap<F> {
70+
impl<const N: usize> DerefMut for OwnedHeap<N> {
3871
fn deref_mut(&mut self) -> &mut Self::Target {
3972
&mut self.heap
4073
}
4174
}
4275

43-
pub fn new_heap() -> OwnedHeap<impl Sized> {
76+
pub fn new_heap() -> OwnedHeap<1000> {
4477
const HEAP_SIZE: usize = 1000;
45-
let mut heap_space = Box::new(Chonk::<HEAP_SIZE>::new());
46-
let data = &mut heap_space.data;
47-
let assumed_location = data.as_mut_ptr().cast();
78+
let (heap_space_ptr, data_ptr) = Chonk::<HEAP_SIZE>::new();
4879

49-
let heap = unsafe { Heap::new(data.as_mut_ptr().cast(), data.len()) };
50-
assert_eq!(heap.bottom(), assumed_location);
80+
let heap = unsafe { Heap::new(data_ptr, HEAP_SIZE) };
81+
assert_eq!(heap.bottom(), data_ptr);
5182
assert_eq!(heap.size(), align_down_size(HEAP_SIZE, size_of::<usize>()));
52-
53-
let drop = move || {
54-
let _ = heap_space;
55-
};
56-
OwnedHeap { heap, _drop: drop }
83+
OwnedHeap {
84+
heap,
85+
_drop: Dropper::new(heap_space_ptr),
86+
}
5787
}
5888

59-
fn new_max_heap() -> OwnedHeap<impl Sized> {
89+
fn new_max_heap() -> OwnedHeap<2048> {
6090
const HEAP_SIZE: usize = 1024;
6191
const HEAP_SIZE_MAX: usize = 2048;
62-
let mut heap_space = Box::new(Chonk::<HEAP_SIZE_MAX>::new());
63-
let data = &mut heap_space.data;
64-
let start_ptr = data.as_mut_ptr().cast();
92+
let (heap_space_ptr, data_ptr) = Chonk::<HEAP_SIZE_MAX>::new();
6593

6694
// Unsafe so that we have provenance over the whole allocation.
67-
let heap = unsafe { Heap::new(start_ptr, HEAP_SIZE) };
68-
assert_eq!(heap.bottom(), start_ptr);
95+
let heap = unsafe { Heap::new(data_ptr, HEAP_SIZE) };
96+
assert_eq!(heap.bottom(), data_ptr);
6997
assert_eq!(heap.size(), HEAP_SIZE);
7098

71-
let drop = move || {
72-
let _ = heap_space;
73-
};
74-
OwnedHeap { heap, _drop: drop }
99+
OwnedHeap {
100+
heap,
101+
_drop: Dropper::new(heap_space_ptr),
102+
}
75103
}
76104

77-
fn new_heap_skip(ct: usize) -> OwnedHeap<impl Sized> {
105+
fn new_heap_skip(ct: usize) -> OwnedHeap<1000> {
78106
const HEAP_SIZE: usize = 1000;
79-
let mut heap_space = Box::new(Chonk::<HEAP_SIZE>::new());
80-
let data = &mut heap_space.data[ct..];
81-
let heap = unsafe { Heap::new(data.as_mut_ptr().cast(), data.len()) };
82-
83-
let drop = move || {
84-
let _ = heap_space;
85-
};
86-
OwnedHeap { heap, _drop: drop }
107+
let (heap_space_ptr, data_ptr) = Chonk::<HEAP_SIZE>::new();
108+
109+
let heap = unsafe { Heap::new(data_ptr.add(ct), HEAP_SIZE - ct) };
110+
OwnedHeap {
111+
heap,
112+
_drop: Dropper::new(heap_space_ptr),
113+
}
87114
}
88115

89116
#[test]
@@ -96,17 +123,18 @@ fn empty() {
96123
#[test]
97124
fn oom() {
98125
const HEAP_SIZE: usize = 1000;
99-
let mut heap_space = Box::new(Chonk::<HEAP_SIZE>::new());
100-
let data = &mut heap_space.data;
101-
let assumed_location = data.as_mut_ptr().cast();
126+
let (heap_space_ptr, data_ptr) = Chonk::<HEAP_SIZE>::new();
102127

103-
let mut heap = unsafe { Heap::new(data.as_mut_ptr().cast(), data.len()) };
104-
assert_eq!(heap.bottom(), assumed_location);
128+
let mut heap = unsafe { Heap::new(data_ptr, HEAP_SIZE) };
129+
assert_eq!(heap.bottom(), data_ptr);
105130
assert_eq!(heap.size(), align_down_size(HEAP_SIZE, size_of::<usize>()));
106131

107132
let layout = Layout::from_size_align(heap.size() + 1, align_of::<usize>());
108133
let addr = heap.allocate_first_fit(layout.unwrap());
109134
assert!(addr.is_err());
135+
136+
// Explicitly unleak the heap allocation
137+
unsafe { Chonk::unleak(heap_space_ptr) };
110138
}
111139

112140
#[test]

0 commit comments

Comments
 (0)