Skip to content

Commit 2526acc

Browse files
committed
Fix issues from review and unsoundness of RawVec::into_box
1 parent 56cbf2f commit 2526acc

File tree

17 files changed

+430
-468
lines changed

17 files changed

+430
-468
lines changed

src/liballoc/alloc.rs

+45-51
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use core::intrinsics::{self, min_align_of_val, size_of_val};
66
use core::ptr::{NonNull, Unique};
7-
use core::usize;
7+
use core::{mem, usize};
88

99
#[stable(feature = "alloc_module", since = "1.28.0")]
1010
#[doc(inline)]
@@ -165,102 +165,96 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
165165
#[unstable(feature = "allocator_api", issue = "32838")]
166166
unsafe impl AllocRef for Global {
167167
#[inline]
168-
fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<(NonNull<u8>, usize), AllocErr> {
169-
let new_size = layout.size();
170-
if new_size == 0 {
171-
Ok((layout.dangling(), 0))
172-
} else {
173-
unsafe {
168+
fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
169+
unsafe {
170+
if layout.size() == 0 {
171+
Ok(MemoryBlock::new(layout.dangling(), layout))
172+
} else {
174173
let raw_ptr = match init {
175174
AllocInit::Uninitialized => alloc(layout),
176175
AllocInit::Zeroed => alloc_zeroed(layout),
177176
};
178177
let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
179-
Ok((ptr, new_size))
178+
Ok(MemoryBlock::new(ptr, layout))
180179
}
181180
}
182181
}
183182

184183
#[inline]
185-
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
186-
if layout.size() != 0 {
187-
dealloc(ptr.as_ptr(), layout)
184+
unsafe fn dealloc(&mut self, memory: MemoryBlock) {
185+
if memory.size() != 0 {
186+
dealloc(memory.ptr().as_ptr(), memory.layout())
188187
}
189188
}
190189

191190
#[inline]
192191
unsafe fn grow(
193192
&mut self,
194-
ptr: NonNull<u8>,
195-
layout: Layout,
193+
memory: &mut MemoryBlock,
196194
new_size: usize,
197195
placement: ReallocPlacement,
198196
init: AllocInit,
199-
) -> Result<(NonNull<u8>, usize), AllocErr> {
200-
let old_size = layout.size();
197+
) -> Result<(), AllocErr> {
198+
let old_size = memory.size();
201199
debug_assert!(
202200
new_size >= old_size,
203-
"`new_size` must be greater than or equal to `layout.size()`"
201+
"`new_size` must be greater than or equal to `memory.size()`"
204202
);
205203

206204
if old_size == new_size {
207-
return Ok((ptr, new_size));
205+
return Ok(());
208206
}
209207

208+
let new_layout = Layout::from_size_align_unchecked(new_size, memory.align());
210209
match placement {
210+
ReallocPlacement::InPlace => return Err(AllocErr),
211+
ReallocPlacement::MayMove if memory.size() == 0 => {
212+
*memory = self.alloc(new_layout, init)?
213+
}
211214
ReallocPlacement::MayMove => {
212-
if old_size == 0 {
213-
self.alloc(Layout::from_size_align_unchecked(new_size, layout.align()), init)
214-
} else {
215-
// `realloc` probably checks for `new_size > old_size` or something similar.
216-
// `new_size` must be greater than or equal to `old_size` due to the safety constraint,
217-
// and `new_size` == `old_size` was caught before
218-
intrinsics::assume(new_size > old_size);
219-
let ptr =
220-
NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)?;
221-
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
222-
init.initialize_offset(ptr, new_layout, old_size);
223-
Ok((ptr, new_size))
224-
}
215+
// `realloc` probably checks for `new_size > old_size` or something similar.
216+
intrinsics::assume(new_size > old_size);
217+
let ptr = realloc(memory.ptr().as_ptr(), memory.layout(), new_size);
218+
*memory = MemoryBlock::new(NonNull::new(ptr).ok_or(AllocErr)?, new_layout);
219+
memory.init_offset(init, old_size);
225220
}
226-
ReallocPlacement::InPlace => Err(AllocErr),
227221
}
222+
Ok(())
228223
}
229224

230225
#[inline]
231226
unsafe fn shrink(
232227
&mut self,
233-
ptr: NonNull<u8>,
234-
layout: Layout,
228+
memory: &mut MemoryBlock,
235229
new_size: usize,
236230
placement: ReallocPlacement,
237-
) -> Result<(NonNull<u8>, usize), AllocErr> {
238-
let old_size = layout.size();
231+
) -> Result<(), AllocErr> {
232+
let old_size = memory.size();
239233
debug_assert!(
240234
new_size <= old_size,
241-
"`new_size` must be smaller than or equal to `layout.size()`"
235+
"`new_size` must be smaller than or equal to `memory.size()`"
242236
);
243237

244238
if old_size == new_size {
245-
return Ok((ptr, new_size));
239+
return Ok(());
246240
}
247241

242+
let new_layout = Layout::from_size_align_unchecked(new_size, memory.align());
248243
match placement {
244+
ReallocPlacement::InPlace => return Err(AllocErr),
245+
ReallocPlacement::MayMove if new_size == 0 => {
246+
let new_memory = MemoryBlock::new(new_layout.dangling(), new_layout);
247+
let old_memory = mem::replace(memory, new_memory);
248+
self.dealloc(old_memory)
249+
}
249250
ReallocPlacement::MayMove => {
250-
let ptr = if new_size == 0 {
251-
self.dealloc(ptr, layout);
252-
layout.dangling()
253-
} else {
254-
// `realloc` probably checks for `new_size > old_size` or something similar.
255-
// `new_size` must be smaller than or equal to `old_size` due to the safety constraint,
256-
// and `new_size` == `old_size` was caught before
257-
intrinsics::assume(new_size < old_size);
258-
NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)?
259-
};
260-
Ok((ptr, new_size))
251+
// `realloc` probably checks for `new_size < old_size` or something similar.
252+
intrinsics::assume(new_size < old_size);
253+
let ptr = realloc(memory.ptr().as_ptr(), memory.layout(), new_size);
254+
*memory = MemoryBlock::new(NonNull::new(ptr).ok_or(AllocErr)?, new_layout);
261255
}
262-
ReallocPlacement::InPlace => Err(AllocErr),
263256
}
257+
Ok(())
264258
}
265259
}
266260

@@ -272,7 +266,7 @@ unsafe impl AllocRef for Global {
272266
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
273267
let layout = Layout::from_size_align_unchecked(size, align);
274268
match Global.alloc(layout, AllocInit::Uninitialized) {
275-
Ok((ptr, _)) => ptr.as_ptr(),
269+
Ok(memory) => memory.ptr().as_ptr(),
276270
Err(_) => handle_alloc_error(layout),
277271
}
278272
}
@@ -288,7 +282,7 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
288282
let size = size_of_val(ptr.as_ref());
289283
let align = min_align_of_val(ptr.as_ref());
290284
let layout = Layout::from_size_align_unchecked(size, align);
291-
Global.dealloc(ptr.cast().into(), layout)
285+
Global.dealloc(MemoryBlock::new(ptr.cast().into(), layout))
292286
}
293287

294288
/// Abort on memory allocation error or failure.

src/liballoc/alloc/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ use test::Bencher;
88
fn allocate_zeroed() {
99
unsafe {
1010
let layout = Layout::from_size_align(1024, 1).unwrap();
11-
let (ptr, _) = Global
11+
let memory = Global
1212
.alloc(layout.clone(), AllocInit::Zeroed)
1313
.unwrap_or_else(|_| handle_alloc_error(layout));
1414

15-
let mut i = ptr.cast::<u8>().as_ptr();
15+
let mut i = memory.ptr().cast::<u8>().as_ptr();
1616
let end = i.add(layout.size());
1717
while i < end {
1818
assert_eq!(*i, 0);
1919
i = i.offset(1);
2020
}
21-
Global.dealloc(ptr, layout);
21+
Global.dealloc(memory);
2222
}
2323
}
2424

src/liballoc/boxed.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ use core::ops::{
143143
};
144144
use core::pin::Pin;
145145
use core::ptr::{self, NonNull, Unique};
146-
use core::slice;
147146
use core::task::{Context, Poll};
148147

149148
use crate::alloc::{self, AllocInit, AllocRef, Global};
@@ -199,7 +198,7 @@ impl<T> Box<T> {
199198
let ptr = Global
200199
.alloc(layout, AllocInit::Uninitialized)
201200
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
202-
.0
201+
.ptr()
203202
.cast();
204203
unsafe { Box::from_raw(ptr.as_ptr()) }
205204
}
@@ -228,7 +227,7 @@ impl<T> Box<T> {
228227
let ptr = Global
229228
.alloc(layout, AllocInit::Zeroed)
230229
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
231-
.0
230+
.ptr()
232231
.cast();
233232
unsafe { Box::from_raw(ptr.as_ptr()) }
234233
}
@@ -265,13 +264,7 @@ impl<T> Box<[T]> {
265264
/// ```
266265
#[unstable(feature = "new_uninit", issue = "63291")]
267266
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
268-
let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
269-
let ptr = Global
270-
.alloc(layout, AllocInit::Uninitialized)
271-
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
272-
.0
273-
.cast();
274-
unsafe { Box::from_raw(slice::from_raw_parts_mut(ptr.as_ptr(), len)) }
267+
unsafe { RawVec::with_capacity(len).into_box(len) }
275268
}
276269
}
277270

@@ -776,7 +769,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
776769
let buf = RawVec::with_capacity(len);
777770
unsafe {
778771
ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
779-
buf.into_box().assume_init()
772+
buf.into_box(slice.len()).assume_init()
780773
}
781774
}
782775
}

src/liballoc/collections/btree/node.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
// - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges.
3232
// This implies that even an empty internal node has at least one edge.
3333

34+
use core::alloc::MemoryBlock;
3435
use core::cmp::Ordering;
3536
use core::marker::PhantomData;
3637
use core::mem::{self, MaybeUninit};
@@ -227,7 +228,10 @@ impl<K, V> Root<K, V> {
227228
}
228229

229230
unsafe {
230-
Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
231+
Global.dealloc(MemoryBlock::new(
232+
NonNull::from(top).cast(),
233+
Layout::new::<InternalNode<K, V>>(),
234+
));
231235
}
232236
}
233237
}
@@ -392,14 +396,14 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
392396
let height = self.height;
393397
let node = self.node;
394398
let ret = self.ascend().ok();
395-
Global.dealloc(
399+
Global.dealloc(MemoryBlock::new(
396400
node.cast(),
397401
if height > 0 {
398402
Layout::new::<InternalNode<K, V>>()
399403
} else {
400404
Layout::new::<LeafNode<K, V>>()
401405
},
402-
);
406+
));
403407
ret
404408
}
405409
}
@@ -1142,7 +1146,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
11421146

11431147
(*left_node.as_leaf_mut()).len += right_len as u16 + 1;
11441148

1145-
if self.node.height > 1 {
1149+
let layout = if self.node.height > 1 {
11461150
ptr::copy_nonoverlapping(
11471151
right_node.cast_unchecked().as_internal().edges.as_ptr(),
11481152
left_node
@@ -1159,10 +1163,11 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
11591163
.correct_parent_link();
11601164
}
11611165

1162-
Global.dealloc(right_node.node.cast(), Layout::new::<InternalNode<K, V>>());
1166+
Layout::new::<InternalNode<K, V>>()
11631167
} else {
1164-
Global.dealloc(right_node.node.cast(), Layout::new::<LeafNode<K, V>>());
1165-
}
1168+
Layout::new::<LeafNode<K, V>>()
1169+
};
1170+
Global.dealloc(MemoryBlock::new(right_node.node.cast(), layout));
11661171

11671172
Handle::new_edge(self.node, self.idx)
11681173
}

src/liballoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#![feature(lang_items)]
101101
#![feature(libc)]
102102
#![cfg_attr(not(bootstrap), feature(negative_impls))]
103+
#![feature(new_uninit)]
103104
#![feature(nll)]
104105
#![feature(optin_builtin_traits)]
105106
#![feature(pattern)]

0 commit comments

Comments
 (0)