Skip to content

Commit 127a11a

Browse files
committed
Auto merge of rust-lang#70362 - TimDiekmann:alloc-overhaul, r=Amanieu
Overhaul of the `AllocRef` trait to match allocator-wg's latest consens; Take 2 GitHub won't let me reopen rust-lang#69889 so I make a new PR. In addition to rust-lang#69889 this fixes the unsoundness of `RawVec::into_box` when using allocators supporting overallocating. Also it uses `MemoryBlock` in `AllocRef` to unify `_in_place` methods by passing `&mut MemoryBlock`. Additionally, `RawVec` now checks for `size_of::<T>()` again and ignore every ZST. The internal capacity of `RawVec` isn't used by ZSTs anymore, as `into_box` now requires a length to be specified. r? @Amanieu fixes rust-lang/wg-allocators#38 fixes rust-lang/wg-allocators#41 fixes rust-lang/wg-allocators#44 fixes rust-lang/wg-allocators#51
2 parents b793f40 + 89ed59d commit 127a11a

File tree

21 files changed

+1445
-1619
lines changed

21 files changed

+1445
-1619
lines changed

src/liballoc/alloc.rs

+76-36
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
#![stable(feature = "alloc_module", since = "1.28.0")]
44

5-
use core::intrinsics::{min_align_of_val, size_of_val};
5+
use core::intrinsics::{self, min_align_of_val, size_of_val};
66
use core::ptr::{NonNull, Unique};
77
use core::usize;
88

@@ -165,11 +165,19 @@ 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) -> Result<(NonNull<u8>, usize), AllocErr> {
169-
if layout.size() == 0 {
170-
Ok((layout.dangling(), 0))
171-
} else {
172-
unsafe { NonNull::new(alloc(layout)).ok_or(AllocErr).map(|p| (p, layout.size())) }
168+
fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
169+
unsafe {
170+
let size = layout.size();
171+
if size == 0 {
172+
Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
173+
} else {
174+
let raw_ptr = match init {
175+
AllocInit::Uninitialized => alloc(layout),
176+
AllocInit::Zeroed => alloc_zeroed(layout),
177+
};
178+
let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
179+
Ok(MemoryBlock { ptr, size })
180+
}
173181
}
174182
}
175183

@@ -181,32 +189,71 @@ unsafe impl AllocRef for Global {
181189
}
182190

183191
#[inline]
184-
unsafe fn realloc(
192+
unsafe fn grow(
185193
&mut self,
186194
ptr: NonNull<u8>,
187195
layout: Layout,
188196
new_size: usize,
189-
) -> Result<(NonNull<u8>, usize), AllocErr> {
190-
match (layout.size(), new_size) {
191-
(0, 0) => Ok((layout.dangling(), 0)),
192-
(0, _) => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
193-
(_, 0) => {
194-
self.dealloc(ptr, layout);
195-
Ok((layout.dangling(), 0))
197+
placement: ReallocPlacement,
198+
init: AllocInit,
199+
) -> Result<MemoryBlock, AllocErr> {
200+
let size = layout.size();
201+
debug_assert!(
202+
new_size >= size,
203+
"`new_size` must be greater than or equal to `memory.size()`"
204+
);
205+
206+
if size == new_size {
207+
return Ok(MemoryBlock { ptr, size });
208+
}
209+
210+
match placement {
211+
ReallocPlacement::InPlace => Err(AllocErr),
212+
ReallocPlacement::MayMove if layout.size() == 0 => {
213+
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
214+
self.alloc(new_layout, init)
215+
}
216+
ReallocPlacement::MayMove => {
217+
// `realloc` probably checks for `new_size > size` or something similar.
218+
intrinsics::assume(new_size > size);
219+
let ptr = realloc(ptr.as_ptr(), layout, new_size);
220+
let memory =
221+
MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
222+
init.init_offset(memory, size);
223+
Ok(memory)
196224
}
197-
(_, _) => NonNull::new(realloc(ptr.as_ptr(), layout, new_size))
198-
.ok_or(AllocErr)
199-
.map(|p| (p, new_size)),
200225
}
201226
}
202227

203228
#[inline]
204-
fn alloc_zeroed(&mut self, layout: Layout) -> Result<(NonNull<u8>, usize), AllocErr> {
205-
if layout.size() == 0 {
206-
Ok((layout.dangling(), 0))
207-
} else {
208-
unsafe {
209-
NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr).map(|p| (p, layout.size()))
229+
unsafe fn shrink(
230+
&mut self,
231+
ptr: NonNull<u8>,
232+
layout: Layout,
233+
new_size: usize,
234+
placement: ReallocPlacement,
235+
) -> Result<MemoryBlock, AllocErr> {
236+
let size = layout.size();
237+
debug_assert!(
238+
new_size <= size,
239+
"`new_size` must be smaller than or equal to `memory.size()`"
240+
);
241+
242+
if size == new_size {
243+
return Ok(MemoryBlock { ptr, size });
244+
}
245+
246+
match placement {
247+
ReallocPlacement::InPlace => Err(AllocErr),
248+
ReallocPlacement::MayMove if new_size == 0 => {
249+
self.dealloc(ptr, layout);
250+
Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
251+
}
252+
ReallocPlacement::MayMove => {
253+
// `realloc` probably checks for `new_size < size` or something similar.
254+
intrinsics::assume(new_size < size);
255+
let ptr = realloc(ptr.as_ptr(), layout, new_size);
256+
Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
210257
}
211258
}
212259
}
@@ -218,14 +265,10 @@ unsafe impl AllocRef for Global {
218265
#[lang = "exchange_malloc"]
219266
#[inline]
220267
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
221-
if size == 0 {
222-
align as *mut u8
223-
} else {
224-
let layout = Layout::from_size_align_unchecked(size, align);
225-
match Global.alloc(layout) {
226-
Ok((ptr, _)) => ptr.as_ptr(),
227-
Err(_) => handle_alloc_error(layout),
228-
}
268+
let layout = Layout::from_size_align_unchecked(size, align);
269+
match Global.alloc(layout, AllocInit::Uninitialized) {
270+
Ok(memory) => memory.ptr.as_ptr(),
271+
Err(_) => handle_alloc_error(layout),
229272
}
230273
}
231274

@@ -239,11 +282,8 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
239282
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
240283
let size = size_of_val(ptr.as_ref());
241284
let align = min_align_of_val(ptr.as_ref());
242-
// We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
243-
if size != 0 {
244-
let layout = Layout::from_size_align_unchecked(size, align);
245-
Global.dealloc(ptr.cast().into(), layout);
246-
}
285+
let layout = Layout::from_size_align_unchecked(size, align);
286+
Global.dealloc(ptr.cast().into(), layout)
247287
}
248288

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

src/liballoc/alloc/tests.rs

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

14-
let mut i = ptr.cast::<u8>().as_ptr();
15+
let mut i = memory.ptr.cast::<u8>().as_ptr();
1516
let end = i.add(layout.size());
1617
while i < end {
1718
assert_eq!(*i, 0);
1819
i = i.offset(1);
1920
}
20-
Global.dealloc(ptr, layout);
21+
Global.dealloc(memory.ptr, layout);
2122
}
2223
}
2324

src/liballoc/boxed.rs

+16-25
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,9 @@ 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

149-
use crate::alloc::{self, AllocRef, Global};
148+
use crate::alloc::{self, AllocInit, AllocRef, Global};
150149
use crate::raw_vec::RawVec;
151150
use crate::str::from_boxed_utf8_unchecked;
152151
use crate::vec::Vec;
@@ -196,14 +195,12 @@ impl<T> Box<T> {
196195
#[unstable(feature = "new_uninit", issue = "63291")]
197196
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
198197
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
199-
unsafe {
200-
let ptr = if layout.size() == 0 {
201-
NonNull::dangling()
202-
} else {
203-
Global.alloc(layout).unwrap_or_else(|_| alloc::handle_alloc_error(layout)).0.cast()
204-
};
205-
Box::from_raw(ptr.as_ptr())
206-
}
198+
let ptr = Global
199+
.alloc(layout, AllocInit::Uninitialized)
200+
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
201+
.ptr
202+
.cast();
203+
unsafe { Box::from_raw(ptr.as_ptr()) }
207204
}
208205

209206
/// Constructs a new `Box` with uninitialized contents, with the memory
@@ -226,11 +223,13 @@ impl<T> Box<T> {
226223
/// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
227224
#[unstable(feature = "new_uninit", issue = "63291")]
228225
pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
229-
unsafe {
230-
let mut uninit = Self::new_uninit();
231-
ptr::write_bytes::<T>(uninit.as_mut_ptr(), 0, 1);
232-
uninit
233-
}
226+
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
227+
let ptr = Global
228+
.alloc(layout, AllocInit::Zeroed)
229+
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
230+
.ptr
231+
.cast();
232+
unsafe { Box::from_raw(ptr.as_ptr()) }
234233
}
235234

236235
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
@@ -265,15 +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-
unsafe {
270-
let ptr = if layout.size() == 0 {
271-
NonNull::dangling()
272-
} else {
273-
Global.alloc(layout).unwrap_or_else(|_| alloc::handle_alloc_error(layout)).0.cast()
274-
};
275-
Box::from_raw(slice::from_raw_parts_mut(ptr.as_ptr(), len))
276-
}
267+
unsafe { RawVec::with_capacity(len).into_box(len) }
277268
}
278269
}
279270

@@ -778,7 +769,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
778769
let buf = RawVec::with_capacity(len);
779770
unsafe {
780771
ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
781-
buf.into_box()
772+
buf.into_box(slice.len()).assume_init()
782773
}
783774
}
784775
}

src/liballoc/collections/btree/node.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1142,7 +1142,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
11421142

11431143
(*left_node.as_leaf_mut()).len += right_len as u16 + 1;
11441144

1145-
if self.node.height > 1 {
1145+
let layout = if self.node.height > 1 {
11461146
ptr::copy_nonoverlapping(
11471147
right_node.cast_unchecked().as_internal().edges.as_ptr(),
11481148
left_node
@@ -1159,10 +1159,11 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
11591159
.correct_parent_link();
11601160
}
11611161

1162-
Global.dealloc(right_node.node.cast(), Layout::new::<InternalNode<K, V>>());
1162+
Layout::new::<InternalNode<K, V>>()
11631163
} else {
1164-
Global.dealloc(right_node.node.cast(), Layout::new::<LeafNode<K, V>>());
1165-
}
1164+
Layout::new::<LeafNode<K, V>>()
1165+
};
1166+
Global.dealloc(right_node.node.cast(), layout);
11661167

11671168
Handle::new_edge(self.node, self.idx)
11681169
}

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)