Skip to content

Commit 56cbf2f

Browse files
committedMar 26, 2020
Overhaul of the AllocRef trait to match allocator-wg's latest consens
1 parent 2fbb075 commit 56cbf2f

File tree

19 files changed

+1408
-1545
lines changed

19 files changed

+1408
-1545
lines changed
 

‎src/liballoc/alloc.rs

+78-33
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 {
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 {
170171
Ok((layout.dangling(), 0))
171172
} else {
172-
unsafe { NonNull::new(alloc(layout)).ok_or(AllocErr).map(|p| (p, layout.size())) }
173+
unsafe {
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((ptr, new_size))
180+
}
173181
}
174182
}
175183

@@ -181,33 +189,77 @@ 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,
197+
placement: ReallocPlacement,
198+
init: AllocInit,
189199
) -> 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))
200+
let old_size = layout.size();
201+
debug_assert!(
202+
new_size >= old_size,
203+
"`new_size` must be greater than or equal to `layout.size()`"
204+
);
205+
206+
if old_size == new_size {
207+
return Ok((ptr, new_size));
208+
}
209+
210+
match placement {
211+
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+
}
196225
}
197-
(_, _) => NonNull::new(realloc(ptr.as_ptr(), layout, new_size))
198-
.ok_or(AllocErr)
199-
.map(|p| (p, new_size)),
226+
ReallocPlacement::InPlace => Err(AllocErr),
200227
}
201228
}
202229

203230
#[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()))
231+
unsafe fn shrink(
232+
&mut self,
233+
ptr: NonNull<u8>,
234+
layout: Layout,
235+
new_size: usize,
236+
placement: ReallocPlacement,
237+
) -> Result<(NonNull<u8>, usize), AllocErr> {
238+
let old_size = layout.size();
239+
debug_assert!(
240+
new_size <= old_size,
241+
"`new_size` must be smaller than or equal to `layout.size()`"
242+
);
243+
244+
if old_size == new_size {
245+
return Ok((ptr, new_size));
246+
}
247+
248+
match placement {
249+
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))
210261
}
262+
ReallocPlacement::InPlace => Err(AllocErr),
211263
}
212264
}
213265
}
@@ -218,14 +270,10 @@ unsafe impl AllocRef for Global {
218270
#[lang = "exchange_malloc"]
219271
#[inline]
220272
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-
}
273+
let layout = Layout::from_size_align_unchecked(size, align);
274+
match Global.alloc(layout, AllocInit::Uninitialized) {
275+
Ok((ptr, _)) => ptr.as_ptr(),
276+
Err(_) => handle_alloc_error(layout),
229277
}
230278
}
231279

@@ -239,11 +287,8 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
239287
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
240288
let size = size_of_val(ptr.as_ref());
241289
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-
}
290+
let layout = Layout::from_size_align_unchecked(size, align);
291+
Global.dealloc(ptr.cast().into(), layout)
247292
}
248293

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

‎src/liballoc/alloc/tests.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ 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 (ptr, _) = Global
12+
.alloc(layout.clone(), AllocInit::Zeroed)
13+
.unwrap_or_else(|_| handle_alloc_error(layout));
1314

1415
let mut i = ptr.cast::<u8>().as_ptr();
1516
let end = i.add(layout.size());

‎src/liballoc/boxed.rs

+21-23
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ use core::ptr::{self, NonNull, Unique};
146146
use core::slice;
147147
use core::task::{Context, Poll};
148148

149-
use crate::alloc::{self, AllocRef, Global};
149+
use crate::alloc::{self, AllocInit, AllocRef, Global};
150150
use crate::raw_vec::RawVec;
151151
use crate::str::from_boxed_utf8_unchecked;
152152
use crate::vec::Vec;
@@ -196,14 +196,12 @@ impl<T> Box<T> {
196196
#[unstable(feature = "new_uninit", issue = "63291")]
197197
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
198198
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-
}
199+
let ptr = Global
200+
.alloc(layout, AllocInit::Uninitialized)
201+
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
202+
.0
203+
.cast();
204+
unsafe { Box::from_raw(ptr.as_ptr()) }
207205
}
208206

209207
/// Constructs a new `Box` with uninitialized contents, with the memory
@@ -226,11 +224,13 @@ impl<T> Box<T> {
226224
/// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
227225
#[unstable(feature = "new_uninit", issue = "63291")]
228226
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-
}
227+
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
228+
let ptr = Global
229+
.alloc(layout, AllocInit::Zeroed)
230+
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
231+
.0
232+
.cast();
233+
unsafe { Box::from_raw(ptr.as_ptr()) }
234234
}
235235

236236
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
@@ -266,14 +266,12 @@ impl<T> Box<[T]> {
266266
#[unstable(feature = "new_uninit", issue = "63291")]
267267
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
268268
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-
}
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)) }
277275
}
278276
}
279277

@@ -778,7 +776,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
778776
let buf = RawVec::with_capacity(len);
779777
unsafe {
780778
ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
781-
buf.into_box()
779+
buf.into_box().assume_init()
782780
}
783781
}
784782
}

‎src/liballoc/raw_vec.rs

+221-347
Large diffs are not rendered by default.

‎src/liballoc/raw_vec/tests.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
use core::ptr::NonNull;
23

34
#[test]
45
fn allocator_param() {
@@ -20,12 +21,16 @@ fn allocator_param() {
2021
fuel: usize,
2122
}
2223
unsafe impl AllocRef for BoundedAlloc {
23-
fn alloc(&mut self, layout: Layout) -> Result<(NonNull<u8>, usize), AllocErr> {
24+
fn alloc(
25+
&mut self,
26+
layout: Layout,
27+
init: AllocInit,
28+
) -> Result<(NonNull<u8>, usize), AllocErr> {
2429
let size = layout.size();
2530
if size > self.fuel {
2631
return Err(AllocErr);
2732
}
28-
match Global.alloc(layout) {
33+
match Global.alloc(layout, init) {
2934
ok @ Ok(_) => {
3035
self.fuel -= size;
3136
ok

‎src/liballoc/rc.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ use core::ptr::{self, NonNull};
252252
use core::slice::{self, from_raw_parts_mut};
253253
use core::usize;
254254

255-
use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout};
255+
use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout};
256256
use crate::string::String;
257257
use crate::vec::Vec;
258258

@@ -936,7 +936,9 @@ impl<T: ?Sized> Rc<T> {
936936
let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
937937

938938
// Allocate for the layout.
939-
let (mem, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
939+
let (mem, _) = Global
940+
.alloc(layout, AllocInit::Uninitialized)
941+
.unwrap_or_else(|_| handle_alloc_error(layout));
940942

941943
// Initialize the RcBox
942944
let inner = mem_to_rcbox(mem.as_ptr());

‎src/liballoc/sync.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use core::sync::atomic;
2525
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
2626
use core::{isize, usize};
2727

28-
use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout};
28+
use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout};
2929
use crate::boxed::Box;
3030
use crate::rc::is_dangling;
3131
use crate::string::String;
@@ -814,7 +814,9 @@ impl<T: ?Sized> Arc<T> {
814814
// reference (see #54908).
815815
let layout = Layout::new::<ArcInner<()>>().extend(value_layout).unwrap().0.pad_to_align();
816816

817-
let (mem, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
817+
let (mem, _) = Global
818+
.alloc(layout, AllocInit::Uninitialized)
819+
.unwrap_or_else(|_| handle_alloc_error(layout));
818820

819821
// Initialize the ArcInner
820822
let inner = mem_to_arcinner(mem.as_ptr());

‎src/liballoc/tests/heap.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::alloc::{AllocRef, Global, Layout, System};
1+
use std::alloc::{AllocInit, AllocRef, Global, Layout, System};
22

33
/// Issue #45955 and #62251.
44
#[test]
@@ -20,7 +20,13 @@ fn check_overalign_requests<T: AllocRef>(mut allocator: T) {
2020
unsafe {
2121
let pointers: Vec<_> = (0..iterations)
2222
.map(|_| {
23-
allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().0
23+
allocator
24+
.alloc(
25+
Layout::from_size_align(size, align).unwrap(),
26+
AllocInit::Uninitialized,
27+
)
28+
.unwrap()
29+
.0
2430
})
2531
.collect();
2632
for &ptr in &pointers {

‎src/liballoc/vec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ impl<T> Vec<T> {
679679
self.shrink_to_fit();
680680
let buf = ptr::read(&self.buf);
681681
mem::forget(self);
682-
buf.into_box()
682+
buf.into_box().assume_init()
683683
}
684684
}
685685

‎src/libcore/alloc.rs

-1,043
This file was deleted.

‎src/libcore/alloc/global.rs

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
use crate::alloc::Layout;
2+
use crate::cmp;
3+
use crate::ptr;
4+
5+
/// A memory allocator that can be registered as the standard library’s default
6+
/// through the `#[global_allocator]` attribute.
7+
///
8+
/// Some of the methods require that a memory block be *currently
9+
/// allocated* via an allocator. This means that:
10+
///
11+
/// * the starting address for that memory block was previously
12+
/// returned by a previous call to an allocation method
13+
/// such as `alloc`, and
14+
///
15+
/// * the memory block has not been subsequently deallocated, where
16+
/// blocks are deallocated either by being passed to a deallocation
17+
/// method such as `dealloc` or by being
18+
/// passed to a reallocation method that returns a non-null pointer.
19+
///
20+
///
21+
/// # Example
22+
///
23+
/// ```no_run
24+
/// use std::alloc::{GlobalAlloc, Layout, alloc};
25+
/// use std::ptr::null_mut;
26+
///
27+
/// struct MyAllocator;
28+
///
29+
/// unsafe impl GlobalAlloc for MyAllocator {
30+
/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
31+
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
32+
/// }
33+
///
34+
/// #[global_allocator]
35+
/// static A: MyAllocator = MyAllocator;
36+
///
37+
/// fn main() {
38+
/// unsafe {
39+
/// assert!(alloc(Layout::new::<u32>()).is_null())
40+
/// }
41+
/// }
42+
/// ```
43+
///
44+
/// # Safety
45+
///
46+
/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
47+
/// implementors must ensure that they adhere to these contracts:
48+
///
49+
/// * It's undefined behavior if global allocators unwind. This restriction may
50+
/// be lifted in the future, but currently a panic from any of these
51+
/// functions may lead to memory unsafety.
52+
///
53+
/// * `Layout` queries and calculations in general must be correct. Callers of
54+
/// this trait are allowed to rely on the contracts defined on each method,
55+
/// and implementors must ensure such contracts remain true.
56+
#[stable(feature = "global_alloc", since = "1.28.0")]
57+
pub unsafe trait GlobalAlloc {
58+
/// Allocate memory as described by the given `layout`.
59+
///
60+
/// Returns a pointer to newly-allocated memory,
61+
/// or null to indicate allocation failure.
62+
///
63+
/// # Safety
64+
///
65+
/// This function is unsafe because undefined behavior can result
66+
/// if the caller does not ensure that `layout` has non-zero size.
67+
///
68+
/// (Extension subtraits might provide more specific bounds on
69+
/// behavior, e.g., guarantee a sentinel address or a null pointer
70+
/// in response to a zero-size allocation request.)
71+
///
72+
/// The allocated block of memory may or may not be initialized.
73+
///
74+
/// # Errors
75+
///
76+
/// Returning a null pointer indicates that either memory is exhausted
77+
/// or `layout` does not meet this allocator's size or alignment constraints.
78+
///
79+
/// Implementations are encouraged to return null on memory
80+
/// exhaustion rather than aborting, but this is not
81+
/// a strict requirement. (Specifically: it is *legal* to
82+
/// implement this trait atop an underlying native allocation
83+
/// library that aborts on memory exhaustion.)
84+
///
85+
/// Clients wishing to abort computation in response to an
86+
/// allocation error are encouraged to call the [`handle_alloc_error`] function,
87+
/// rather than directly invoking `panic!` or similar.
88+
///
89+
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
90+
#[stable(feature = "global_alloc", since = "1.28.0")]
91+
unsafe fn alloc(&self, layout: Layout) -> *mut u8;
92+
93+
/// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
94+
///
95+
/// # Safety
96+
///
97+
/// This function is unsafe because undefined behavior can result
98+
/// if the caller does not ensure all of the following:
99+
///
100+
/// * `ptr` must denote a block of memory currently allocated via
101+
/// this allocator,
102+
///
103+
/// * `layout` must be the same layout that was used
104+
/// to allocate that block of memory,
105+
#[stable(feature = "global_alloc", since = "1.28.0")]
106+
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
107+
108+
/// Behaves like `alloc`, but also ensures that the contents
109+
/// are set to zero before being returned.
110+
///
111+
/// # Safety
112+
///
113+
/// This function is unsafe for the same reasons that `alloc` is.
114+
/// However the allocated block of memory is guaranteed to be initialized.
115+
///
116+
/// # Errors
117+
///
118+
/// Returning a null pointer indicates that either memory is exhausted
119+
/// or `layout` does not meet allocator's size or alignment constraints,
120+
/// just as in `alloc`.
121+
///
122+
/// Clients wishing to abort computation in response to an
123+
/// allocation error are encouraged to call the [`handle_alloc_error`] function,
124+
/// rather than directly invoking `panic!` or similar.
125+
///
126+
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
127+
#[stable(feature = "global_alloc", since = "1.28.0")]
128+
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
129+
let size = layout.size();
130+
let ptr = self.alloc(layout);
131+
if !ptr.is_null() {
132+
ptr::write_bytes(ptr, 0, size);
133+
}
134+
ptr
135+
}
136+
137+
/// Shrink or grow a block of memory to the given `new_size`.
138+
/// The block is described by the given `ptr` pointer and `layout`.
139+
///
140+
/// If this returns a non-null pointer, then ownership of the memory block
141+
/// referenced by `ptr` has been transferred to this allocator.
142+
/// The memory may or may not have been deallocated,
143+
/// and should be considered unusable (unless of course it was
144+
/// transferred back to the caller again via the return value of
145+
/// this method). The new memory block is allocated with `layout`, but
146+
/// with the `size` updated to `new_size`.
147+
///
148+
/// If this method returns null, then ownership of the memory
149+
/// block has not been transferred to this allocator, and the
150+
/// contents of the memory block are unaltered.
151+
///
152+
/// # Safety
153+
///
154+
/// This function is unsafe because undefined behavior can result
155+
/// if the caller does not ensure all of the following:
156+
///
157+
/// * `ptr` must be currently allocated via this allocator,
158+
///
159+
/// * `layout` must be the same layout that was used
160+
/// to allocate that block of memory,
161+
///
162+
/// * `new_size` must be greater than zero.
163+
///
164+
/// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
165+
/// must not overflow (i.e., the rounded value must be less than `usize::MAX`).
166+
///
167+
/// (Extension subtraits might provide more specific bounds on
168+
/// behavior, e.g., guarantee a sentinel address or a null pointer
169+
/// in response to a zero-size allocation request.)
170+
///
171+
/// # Errors
172+
///
173+
/// Returns null if the new layout does not meet the size
174+
/// and alignment constraints of the allocator, or if reallocation
175+
/// otherwise fails.
176+
///
177+
/// Implementations are encouraged to return null on memory
178+
/// exhaustion rather than panicking or aborting, but this is not
179+
/// a strict requirement. (Specifically: it is *legal* to
180+
/// implement this trait atop an underlying native allocation
181+
/// library that aborts on memory exhaustion.)
182+
///
183+
/// Clients wishing to abort computation in response to a
184+
/// reallocation error are encouraged to call the [`handle_alloc_error`] function,
185+
/// rather than directly invoking `panic!` or similar.
186+
///
187+
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
188+
#[stable(feature = "global_alloc", since = "1.28.0")]
189+
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
190+
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
191+
let new_ptr = self.alloc(new_layout);
192+
if !new_ptr.is_null() {
193+
ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
194+
self.dealloc(ptr, layout);
195+
}
196+
new_ptr
197+
}
198+
}

‎src/libcore/alloc/layout.rs

+345
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
// ignore-tidy-undocumented-unsafe
2+
3+
use crate::cmp;
4+
use crate::fmt;
5+
use crate::mem;
6+
use crate::num::NonZeroUsize;
7+
use crate::ptr::NonNull;
8+
9+
const fn size_align<T>() -> (usize, usize) {
10+
(mem::size_of::<T>(), mem::align_of::<T>())
11+
}
12+
13+
/// Layout of a block of memory.
14+
///
15+
/// An instance of `Layout` describes a particular layout of memory.
16+
/// You build a `Layout` up as an input to give to an allocator.
17+
///
18+
/// All layouts have an associated size and a power-of-two alignment.
19+
///
20+
/// (Note that layouts are *not* required to have non-zero size,
21+
/// even though `GlobalAlloc` requires that all memory requests
22+
/// be non-zero in size. A caller must either ensure that conditions
23+
/// like this are met, use specific allocators with looser
24+
/// requirements, or use the more lenient `AllocRef` interface.)
25+
#[stable(feature = "alloc_layout", since = "1.28.0")]
26+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
27+
#[lang = "alloc_layout"]
28+
pub struct Layout {
29+
// size of the requested block of memory, measured in bytes.
30+
size_: usize,
31+
32+
// alignment of the requested block of memory, measured in bytes.
33+
// we ensure that this is always a power-of-two, because API's
34+
// like `posix_memalign` require it and it is a reasonable
35+
// constraint to impose on Layout constructors.
36+
//
37+
// (However, we do not analogously require `align >= sizeof(void*)`,
38+
// even though that is *also* a requirement of `posix_memalign`.)
39+
align_: NonZeroUsize,
40+
}
41+
42+
impl Layout {
43+
/// Constructs a `Layout` from a given `size` and `align`,
44+
/// or returns `LayoutErr` if any of the following conditions
45+
/// are not met:
46+
///
47+
/// * `align` must not be zero,
48+
///
49+
/// * `align` must be a power of two,
50+
///
51+
/// * `size`, when rounded up to the nearest multiple of `align`,
52+
/// must not overflow (i.e., the rounded value must be less than
53+
/// or equal to `usize::MAX`).
54+
#[stable(feature = "alloc_layout", since = "1.28.0")]
55+
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
56+
#[inline]
57+
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
58+
if !align.is_power_of_two() {
59+
return Err(LayoutErr { private: () });
60+
}
61+
62+
// (power-of-two implies align != 0.)
63+
64+
// Rounded up size is:
65+
// size_rounded_up = (size + align - 1) & !(align - 1);
66+
//
67+
// We know from above that align != 0. If adding (align - 1)
68+
// does not overflow, then rounding up will be fine.
69+
//
70+
// Conversely, &-masking with !(align - 1) will subtract off
71+
// only low-order-bits. Thus if overflow occurs with the sum,
72+
// the &-mask cannot subtract enough to undo that overflow.
73+
//
74+
// Above implies that checking for summation overflow is both
75+
// necessary and sufficient.
76+
if size > usize::MAX - (align - 1) {
77+
return Err(LayoutErr { private: () });
78+
}
79+
80+
unsafe { Ok(Layout::from_size_align_unchecked(size, align)) }
81+
}
82+
83+
/// Creates a layout, bypassing all checks.
84+
///
85+
/// # Safety
86+
///
87+
/// This function is unsafe as it does not verify the preconditions from
88+
/// [`Layout::from_size_align`](#method.from_size_align).
89+
#[stable(feature = "alloc_layout", since = "1.28.0")]
90+
#[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")]
91+
#[inline]
92+
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
93+
Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
94+
}
95+
96+
/// The minimum size in bytes for a memory block of this layout.
97+
#[stable(feature = "alloc_layout", since = "1.28.0")]
98+
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
99+
#[inline]
100+
pub const fn size(&self) -> usize {
101+
self.size_
102+
}
103+
104+
/// The minimum byte alignment for a memory block of this layout.
105+
#[stable(feature = "alloc_layout", since = "1.28.0")]
106+
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
107+
#[inline]
108+
pub const fn align(&self) -> usize {
109+
self.align_.get()
110+
}
111+
112+
/// Constructs a `Layout` suitable for holding a value of type `T`.
113+
#[stable(feature = "alloc_layout", since = "1.28.0")]
114+
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
115+
#[inline]
116+
pub const fn new<T>() -> Self {
117+
let (size, align) = size_align::<T>();
118+
// Note that the align is guaranteed by rustc to be a power of two and
119+
// the size+align combo is guaranteed to fit in our address space. As a
120+
// result use the unchecked constructor here to avoid inserting code
121+
// that panics if it isn't optimized well enough.
122+
unsafe { Layout::from_size_align_unchecked(size, align) }
123+
}
124+
125+
/// Produces layout describing a record that could be used to
126+
/// allocate backing structure for `T` (which could be a trait
127+
/// or other unsized type like a slice).
128+
#[stable(feature = "alloc_layout", since = "1.28.0")]
129+
#[inline]
130+
pub fn for_value<T: ?Sized>(t: &T) -> Self {
131+
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
132+
// See rationale in `new` for why this is using an unsafe variant below
133+
debug_assert!(Layout::from_size_align(size, align).is_ok());
134+
unsafe { Layout::from_size_align_unchecked(size, align) }
135+
}
136+
137+
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
138+
///
139+
/// Note that the pointer value may potentially represent a valid pointer,
140+
/// which means this must not be used as a "not yet initialized"
141+
/// sentinel value. Types that lazily allocate must track initialization by
142+
/// some other means.
143+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
144+
pub const fn dangling(&self) -> NonNull<u8> {
145+
// align is non-zero and a power of two
146+
unsafe { NonNull::new_unchecked(self.align() as *mut u8) }
147+
}
148+
149+
/// Creates a layout describing the record that can hold a value
150+
/// of the same layout as `self`, but that also is aligned to
151+
/// alignment `align` (measured in bytes).
152+
///
153+
/// If `self` already meets the prescribed alignment, then returns
154+
/// `self`.
155+
///
156+
/// Note that this method does not add any padding to the overall
157+
/// size, regardless of whether the returned layout has a different
158+
/// alignment. In other words, if `K` has size 16, `K.align_to(32)`
159+
/// will *still* have size 16.
160+
///
161+
/// Returns an error if the combination of `self.size()` and the given
162+
/// `align` violates the conditions listed in
163+
/// [`Layout::from_size_align`](#method.from_size_align).
164+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
165+
#[inline]
166+
pub fn align_to(&self, align: usize) -> Result<Self, LayoutErr> {
167+
Layout::from_size_align(self.size(), cmp::max(self.align(), align))
168+
}
169+
170+
/// Returns the amount of padding we must insert after `self`
171+
/// to ensure that the following address will satisfy `align`
172+
/// (measured in bytes).
173+
///
174+
/// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)`
175+
/// returns 3, because that is the minimum number of bytes of
176+
/// padding required to get a 4-aligned address (assuming that the
177+
/// corresponding memory block starts at a 4-aligned address).
178+
///
179+
/// The return value of this function has no meaning if `align` is
180+
/// not a power-of-two.
181+
///
182+
/// Note that the utility of the returned value requires `align`
183+
/// to be less than or equal to the alignment of the starting
184+
/// address for the whole allocated block of memory. One way to
185+
/// satisfy this constraint is to ensure `align <= self.align()`.
186+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
187+
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
188+
#[inline]
189+
pub const fn padding_needed_for(&self, align: usize) -> usize {
190+
let len = self.size();
191+
192+
// Rounded up value is:
193+
// len_rounded_up = (len + align - 1) & !(align - 1);
194+
// and then we return the padding difference: `len_rounded_up - len`.
195+
//
196+
// We use modular arithmetic throughout:
197+
//
198+
// 1. align is guaranteed to be > 0, so align - 1 is always
199+
// valid.
200+
//
201+
// 2. `len + align - 1` can overflow by at most `align - 1`,
202+
// so the &-mask with `!(align - 1)` will ensure that in the
203+
// case of overflow, `len_rounded_up` will itself be 0.
204+
// Thus the returned padding, when added to `len`, yields 0,
205+
// which trivially satisfies the alignment `align`.
206+
//
207+
// (Of course, attempts to allocate blocks of memory whose
208+
// size and padding overflow in the above manner should cause
209+
// the allocator to yield an error anyway.)
210+
211+
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
212+
len_rounded_up.wrapping_sub(len)
213+
}
214+
215+
/// Creates a layout by rounding the size of this layout up to a multiple
216+
/// of the layout's alignment.
217+
///
218+
/// This is equivalent to adding the result of `padding_needed_for`
219+
/// to the layout's current size.
220+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
221+
#[inline]
222+
pub fn pad_to_align(&self) -> Layout {
223+
let pad = self.padding_needed_for(self.align());
224+
// This cannot overflow. Quoting from the invariant of Layout:
225+
// > `size`, when rounded up to the nearest multiple of `align`,
226+
// > must not overflow (i.e., the rounded value must be less than
227+
// > `usize::MAX`)
228+
let new_size = self.size() + pad;
229+
230+
Layout::from_size_align(new_size, self.align()).unwrap()
231+
}
232+
233+
/// Creates a layout describing the record for `n` instances of
234+
/// `self`, with a suitable amount of padding between each to
235+
/// ensure that each instance is given its requested size and
236+
/// alignment. On success, returns `(k, offs)` where `k` is the
237+
/// layout of the array and `offs` is the distance between the start
238+
/// of each element in the array.
239+
///
240+
/// On arithmetic overflow, returns `LayoutErr`.
241+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
242+
#[inline]
243+
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
244+
// This cannot overflow. Quoting from the invariant of Layout:
245+
// > `size`, when rounded up to the nearest multiple of `align`,
246+
// > must not overflow (i.e., the rounded value must be less than
247+
// > `usize::MAX`)
248+
let padded_size = self.size() + self.padding_needed_for(self.align());
249+
let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?;
250+
251+
unsafe {
252+
// self.align is already known to be valid and alloc_size has been
253+
// padded already.
254+
Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size))
255+
}
256+
}
257+
258+
/// Creates a layout describing the record for `self` followed by
259+
/// `next`, including any necessary padding to ensure that `next`
260+
/// will be properly aligned. Note that the resulting layout will
261+
/// satisfy the alignment properties of both `self` and `next`.
262+
///
263+
/// The resulting layout will be the same as that of a C struct containing
264+
/// two fields with the layouts of `self` and `next`, in that order.
265+
///
266+
/// Returns `Some((k, offset))`, where `k` is layout of the concatenated
267+
/// record and `offset` is the relative location, in bytes, of the
268+
/// start of the `next` embedded within the concatenated record
269+
/// (assuming that the record itself starts at offset 0).
270+
///
271+
/// On arithmetic overflow, returns `LayoutErr`.
272+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
273+
#[inline]
274+
pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
275+
let new_align = cmp::max(self.align(), next.align());
276+
let pad = self.padding_needed_for(next.align());
277+
278+
let offset = self.size().checked_add(pad).ok_or(LayoutErr { private: () })?;
279+
let new_size = offset.checked_add(next.size()).ok_or(LayoutErr { private: () })?;
280+
281+
let layout = Layout::from_size_align(new_size, new_align)?;
282+
Ok((layout, offset))
283+
}
284+
285+
/// Creates a layout describing the record for `n` instances of
286+
/// `self`, with no padding between each instance.
287+
///
288+
/// Note that, unlike `repeat`, `repeat_packed` does not guarantee
289+
/// that the repeated instances of `self` will be properly
290+
/// aligned, even if a given instance of `self` is properly
291+
/// aligned. In other words, if the layout returned by
292+
/// `repeat_packed` is used to allocate an array, it is not
293+
/// guaranteed that all elements in the array will be properly
294+
/// aligned.
295+
///
296+
/// On arithmetic overflow, returns `LayoutErr`.
297+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
298+
#[inline]
299+
pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
300+
let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
301+
Layout::from_size_align(size, self.align())
302+
}
303+
304+
/// Creates a layout describing the record for `self` followed by
305+
/// `next` with no additional padding between the two. Since no
306+
/// padding is inserted, the alignment of `next` is irrelevant,
307+
/// and is not incorporated *at all* into the resulting layout.
308+
///
309+
/// On arithmetic overflow, returns `LayoutErr`.
310+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
311+
#[inline]
312+
pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutErr> {
313+
let new_size = self.size().checked_add(next.size()).ok_or(LayoutErr { private: () })?;
314+
Layout::from_size_align(new_size, self.align())
315+
}
316+
317+
/// Creates a layout describing the record for a `[T; n]`.
318+
///
319+
/// On arithmetic overflow, returns `LayoutErr`.
320+
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
321+
#[inline]
322+
pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
323+
Layout::new::<T>().repeat(n).map(|(k, offs)| {
324+
debug_assert!(offs == mem::size_of::<T>());
325+
k
326+
})
327+
}
328+
}
329+
330+
/// The parameters given to `Layout::from_size_align`
331+
/// or some other `Layout` constructor
332+
/// do not satisfy its documented constraints.
333+
#[stable(feature = "alloc_layout", since = "1.28.0")]
334+
#[derive(Clone, PartialEq, Eq, Debug)]
335+
pub struct LayoutErr {
336+
private: (),
337+
}
338+
339+
// (we need this for downstream impl of trait Error)
340+
#[stable(feature = "alloc_layout", since = "1.28.0")]
341+
impl fmt::Display for LayoutErr {
342+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343+
f.write_str("invalid parameters to Layout::from_size_align")
344+
}
345+
}

‎src/libcore/alloc/mod.rs

+376
Large diffs are not rendered by default.

‎src/libstd/alloc.rs

+77-32
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
6262
#![stable(feature = "alloc_module", since = "1.28.0")]
6363

64+
use core::intrinsics;
6465
use core::ptr::NonNull;
6566
use core::sync::atomic::{AtomicPtr, Ordering};
6667
use core::{mem, ptr};
@@ -133,60 +134,106 @@ pub use alloc_crate::alloc::*;
133134
#[derive(Debug, Default, Copy, Clone)]
134135
pub struct System;
135136

136-
// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl,
137-
// which is in `std::sys::*::alloc`.
138137
#[unstable(feature = "allocator_api", issue = "32838")]
139138
unsafe impl AllocRef for System {
140139
#[inline]
141-
fn alloc(&mut self, layout: Layout) -> Result<(NonNull<u8>, usize), AllocErr> {
142-
if layout.size() == 0 {
140+
fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<(NonNull<u8>, usize), AllocErr> {
141+
let new_size = layout.size();
142+
if new_size == 0 {
143143
Ok((layout.dangling(), 0))
144144
} else {
145145
unsafe {
146-
NonNull::new(GlobalAlloc::alloc(self, layout))
147-
.ok_or(AllocErr)
148-
.map(|p| (p, layout.size()))
146+
let raw_ptr = match init {
147+
AllocInit::Uninitialized => GlobalAlloc::alloc(self, layout),
148+
AllocInit::Zeroed => GlobalAlloc::alloc_zeroed(self, layout),
149+
};
150+
let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
151+
Ok((ptr, new_size))
149152
}
150153
}
151154
}
152155

153156
#[inline]
154-
fn alloc_zeroed(&mut self, layout: Layout) -> Result<(NonNull<u8>, usize), AllocErr> {
155-
if layout.size() == 0 {
156-
Ok((layout.dangling(), 0))
157-
} else {
158-
unsafe {
159-
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout))
160-
.ok_or(AllocErr)
161-
.map(|p| (p, layout.size()))
162-
}
157+
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
158+
if layout.size() != 0 {
159+
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
163160
}
164161
}
165162

166163
#[inline]
167-
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
168-
if layout.size() != 0 {
169-
GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
164+
unsafe fn grow(
165+
&mut self,
166+
ptr: NonNull<u8>,
167+
layout: Layout,
168+
new_size: usize,
169+
placement: ReallocPlacement,
170+
init: AllocInit,
171+
) -> Result<(NonNull<u8>, usize), AllocErr> {
172+
let old_size = layout.size();
173+
debug_assert!(
174+
new_size >= old_size,
175+
"`new_size` must be greater than or equal to `layout.size()`"
176+
);
177+
178+
if old_size == new_size {
179+
return Ok((ptr, new_size));
180+
}
181+
182+
match placement {
183+
ReallocPlacement::MayMove => {
184+
if old_size == 0 {
185+
self.alloc(Layout::from_size_align_unchecked(new_size, layout.align()), init)
186+
} else {
187+
// `realloc` probably checks for `new_size > old_size` or something similar.
188+
// `new_size` must be greater than or equal to `old_size` due to the safety constraint,
189+
// and `new_size` == `old_size` was caught before
190+
intrinsics::assume(new_size > old_size);
191+
let ptr =
192+
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size))
193+
.ok_or(AllocErr)?;
194+
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
195+
init.initialize_offset(ptr, new_layout, old_size);
196+
Ok((ptr, new_size))
197+
}
198+
}
199+
ReallocPlacement::InPlace => Err(AllocErr),
170200
}
171201
}
172202

173203
#[inline]
174-
unsafe fn realloc(
204+
unsafe fn shrink(
175205
&mut self,
176206
ptr: NonNull<u8>,
177207
layout: Layout,
178208
new_size: usize,
209+
placement: ReallocPlacement,
179210
) -> Result<(NonNull<u8>, usize), AllocErr> {
180-
match (layout.size(), new_size) {
181-
(0, 0) => Ok((layout.dangling(), 0)),
182-
(0, _) => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
183-
(_, 0) => {
184-
self.dealloc(ptr, layout);
185-
Ok((layout.dangling(), 0))
211+
let old_size = layout.size();
212+
debug_assert!(
213+
new_size <= old_size,
214+
"`new_size` must be smaller than or equal to `layout.size()`"
215+
);
216+
217+
if old_size == new_size {
218+
return Ok((ptr, new_size));
219+
}
220+
221+
match placement {
222+
ReallocPlacement::MayMove => {
223+
let ptr = if new_size == 0 {
224+
self.dealloc(ptr, layout);
225+
layout.dangling()
226+
} else {
227+
// `realloc` probably checks for `new_size > old_size` or something similar.
228+
// `new_size` must be smaller than or equal to `old_size` due to the safety constraint,
229+
// and `new_size` == `old_size` was caught before
230+
intrinsics::assume(new_size < old_size);
231+
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size))
232+
.ok_or(AllocErr)?
233+
};
234+
Ok((ptr, new_size))
186235
}
187-
(_, _) => NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size))
188-
.ok_or(AllocErr)
189-
.map(|p| (p, new_size)),
236+
ReallocPlacement::InPlace => Err(AllocErr),
190237
}
191238
}
192239
}
@@ -238,9 +285,7 @@ pub fn rust_oom(layout: Layout) -> ! {
238285
let hook: fn(Layout) =
239286
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
240287
hook(layout);
241-
unsafe {
242-
crate::sys::abort_internal();
243-
}
288+
unsafe { crate::sys::abort_internal() }
244289
}
245290

246291
#[cfg(not(test))]

‎src/libstd/error.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
use core::array;
1717

18-
use crate::alloc::{AllocErr, CannotReallocInPlace, LayoutErr};
18+
use crate::alloc::{AllocErr, LayoutErr};
1919
use crate::any::TypeId;
2020
use crate::backtrace::Backtrace;
2121
use crate::borrow::Cow;
@@ -409,13 +409,6 @@ impl Error for AllocErr {}
409409
)]
410410
impl Error for LayoutErr {}
411411

412-
#[unstable(
413-
feature = "allocator_api",
414-
reason = "the precise API and guarantees it provides may be tweaked.",
415-
issue = "32838"
416-
)]
417-
impl Error for CannotReallocInPlace {}
418-
419412
#[stable(feature = "rust1", since = "1.0.0")]
420413
impl Error for str::ParseBoolError {
421414
#[allow(deprecated)]

‎src/test/ui/allocator/custom.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
extern crate helper;
99

10-
use std::alloc::{self, Global, AllocRef, System, Layout};
10+
use std::alloc::{self, AllocInit, AllocRef, Global, Layout, System};
1111
use std::sync::atomic::{AtomicUsize, Ordering};
1212

1313
static HITS: AtomicUsize = AtomicUsize::new(0);
@@ -37,7 +37,7 @@ fn main() {
3737
unsafe {
3838
let layout = Layout::from_size_align(4, 2).unwrap();
3939

40-
let (ptr, _) = Global.alloc(layout.clone()).unwrap();
40+
let (ptr, _) = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
4141
helper::work_with(&ptr);
4242
assert_eq!(HITS.load(Ordering::SeqCst), n + 1);
4343
Global.dealloc(ptr, layout.clone());
@@ -49,7 +49,7 @@ fn main() {
4949
drop(s);
5050
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
5151

52-
let (ptr, _) = System.alloc(layout.clone()).unwrap();
52+
let (ptr, _) = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
5353
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
5454
helper::work_with(&ptr);
5555
System.dealloc(ptr, layout);

‎src/test/ui/allocator/xcrate-use.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
extern crate custom;
1010
extern crate helper;
1111

12-
use std::alloc::{Global, AllocRef, System, Layout};
13-
use std::sync::atomic::{Ordering, AtomicUsize};
12+
use std::alloc::{AllocInit, AllocRef, Global, Layout, System};
13+
use std::sync::atomic::{AtomicUsize, Ordering};
1414

1515
#[global_allocator]
1616
static GLOBAL: custom::A = custom::A(AtomicUsize::new(0));
@@ -20,13 +20,13 @@ fn main() {
2020
let n = GLOBAL.0.load(Ordering::SeqCst);
2121
let layout = Layout::from_size_align(4, 2).unwrap();
2222

23-
let (ptr, _) = Global.alloc(layout.clone()).unwrap();
23+
let (ptr, _) = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
2424
helper::work_with(&ptr);
2525
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
2626
Global.dealloc(ptr, layout.clone());
2727
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
2828

29-
let (ptr, _) = System.alloc(layout.clone()).unwrap();
29+
let (ptr, _) = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap();
3030
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
3131
helper::work_with(&ptr);
3232
System.dealloc(ptr, layout);

‎src/test/ui/realloc-16687.rs

+50-34
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#![feature(allocator_api)]
88

9-
use std::alloc::{Global, AllocRef, Layout, handle_alloc_error};
9+
use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout, ReallocPlacement};
1010
use std::ptr::{self, NonNull};
1111

1212
fn main() {
@@ -16,32 +16,34 @@ fn main() {
1616
}
1717

1818
unsafe fn test_triangle() -> bool {
19-
static COUNT : usize = 16;
19+
static COUNT: usize = 16;
2020
let mut ascend = vec![ptr::null_mut(); COUNT];
2121
let ascend = &mut *ascend;
22-
static ALIGN : usize = 1;
22+
static ALIGN: usize = 1;
2323

2424
// Checks that `ascend` forms triangle of ascending size formed
2525
// from pairs of rows (where each pair of rows is equally sized),
2626
// and the elements of the triangle match their row-pair index.
2727
unsafe fn sanity_check(ascend: &[*mut u8]) {
2828
for i in 0..COUNT / 2 {
29-
let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
29+
let (p0, p1, size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
3030
for j in 0..size {
3131
assert_eq!(*p0.add(j), i as u8);
3232
assert_eq!(*p1.add(j), i as u8);
3333
}
3434
}
3535
}
3636

37-
static PRINT : bool = false;
37+
static PRINT: bool = false;
3838

3939
unsafe fn allocate(layout: Layout) -> *mut u8 {
4040
if PRINT {
4141
println!("allocate({:?})", layout);
4242
}
4343

44-
let (ptr, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
44+
let (ptr, _) = Global
45+
.alloc(layout, AllocInit::Uninitialized)
46+
.unwrap_or_else(|_| handle_alloc_error(layout));
4547

4648
if PRINT {
4749
println!("allocate({:?}) = {:?}", layout, ptr);
@@ -63,33 +65,47 @@ unsafe fn test_triangle() -> bool {
6365
println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
6466
}
6567

66-
let (ptr, _) = Global.realloc(NonNull::new_unchecked(ptr), old, new.size())
67-
.unwrap_or_else(|_| handle_alloc_error(
68-
Layout::from_size_align_unchecked(new.size(), old.align())
69-
));
68+
let allocation = if new.size() > old.size() {
69+
Global.grow(
70+
NonNull::new_unchecked(ptr),
71+
old,
72+
new.size(),
73+
ReallocPlacement::MayMove,
74+
AllocInit::Uninitialized,
75+
)
76+
} else if new.size() < old.size() {
77+
Global.shrink(NonNull::new_unchecked(ptr), old, new.size(), ReallocPlacement::MayMove)
78+
} else {
79+
return ptr;
80+
};
81+
82+
let (ptr, _) = allocation.unwrap_or_else(|_| {
83+
handle_alloc_error(Layout::from_size_align_unchecked(new.size(), old.align()))
84+
});
7085

7186
if PRINT {
72-
println!("reallocate({:?}, old={:?}, new={:?}) = {:?}",
73-
ptr, old, new, ptr);
87+
println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ptr);
7488
}
7589
ptr.cast().as_ptr()
7690
}
7791

78-
fn idx_to_size(i: usize) -> usize { (i+1) * 10 }
92+
fn idx_to_size(i: usize) -> usize {
93+
(i + 1) * 10
94+
}
7995

8096
// Allocate pairs of rows that form a triangle shape. (Hope is
8197
// that at least two rows will be allocated near each other, so
8298
// that we trigger the bug (a buffer overrun) in an observable
8399
// way.)
84100
for i in 0..COUNT / 2 {
85101
let size = idx_to_size(i);
86-
ascend[2*i] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
87-
ascend[2*i+1] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
102+
ascend[2 * i] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
103+
ascend[2 * i + 1] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
88104
}
89105

90106
// Initialize each pair of rows to distinct value.
91107
for i in 0..COUNT / 2 {
92-
let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
108+
let (p0, p1, size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
93109
for j in 0..size {
94110
*p0.add(j) = i as u8;
95111
*p1.add(j) = i as u8;
@@ -104,8 +120,8 @@ unsafe fn test_triangle() -> bool {
104120

105121
for i in 0..COUNT / 2 {
106122
let size = idx_to_size(i);
107-
deallocate(ascend[2*i], Layout::from_size_align(size, ALIGN).unwrap());
108-
deallocate(ascend[2*i+1], Layout::from_size_align(size, ALIGN).unwrap());
123+
deallocate(ascend[2 * i], Layout::from_size_align(size, ALIGN).unwrap());
124+
deallocate(ascend[2 * i + 1], Layout::from_size_align(size, ALIGN).unwrap());
109125
}
110126

111127
return true;
@@ -115,68 +131,68 @@ unsafe fn test_triangle() -> bool {
115131
// realloc'ing each row from top to bottom, and checking all the
116132
// rows as we go.
117133
unsafe fn test_1(ascend: &mut [*mut u8]) {
118-
let new_size = idx_to_size(COUNT-1);
134+
let new_size = idx_to_size(COUNT - 1);
119135
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
120136
for i in 0..COUNT / 2 {
121-
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
137+
let (p0, p1, old_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
122138
assert!(old_size < new_size);
123139
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
124140

125-
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
141+
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
126142
sanity_check(&*ascend);
127143

128-
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
144+
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
129145
sanity_check(&*ascend);
130146
}
131147
}
132148

133149
// Test 2: turn the square back into a triangle, top to bottom.
134150
unsafe fn test_2(ascend: &mut [*mut u8]) {
135-
let old_size = idx_to_size(COUNT-1);
151+
let old_size = idx_to_size(COUNT - 1);
136152
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
137153
for i in 0..COUNT / 2 {
138-
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
154+
let (p0, p1, new_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
139155
assert!(new_size < old_size);
140156
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
141157

142-
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
158+
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
143159
sanity_check(&*ascend);
144160

145-
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
161+
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
146162
sanity_check(&*ascend);
147163
}
148164
}
149165

150166
// Test 3: turn triangle into a square, bottom to top.
151167
unsafe fn test_3(ascend: &mut [*mut u8]) {
152-
let new_size = idx_to_size(COUNT-1);
168+
let new_size = idx_to_size(COUNT - 1);
153169
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
154170
for i in (0..COUNT / 2).rev() {
155-
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
171+
let (p0, p1, old_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
156172
assert!(old_size < new_size);
157173
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
158174

159-
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
175+
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
160176
sanity_check(&*ascend);
161177

162-
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
178+
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
163179
sanity_check(&*ascend);
164180
}
165181
}
166182

167183
// Test 4: turn the square back into a triangle, bottom to top.
168184
unsafe fn test_4(ascend: &mut [*mut u8]) {
169-
let old_size = idx_to_size(COUNT-1);
185+
let old_size = idx_to_size(COUNT - 1);
170186
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
171187
for i in (0..COUNT / 2).rev() {
172-
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
188+
let (p0, p1, new_size) = (ascend[2 * i], ascend[2 * i + 1], idx_to_size(i));
173189
assert!(new_size < old_size);
174190
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
175191

176-
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
192+
ascend[2 * i + 1] = reallocate(p1, old.clone(), new.clone());
177193
sanity_check(&*ascend);
178194

179-
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
195+
ascend[2 * i] = reallocate(p0, old.clone(), new.clone());
180196
sanity_check(&*ascend);
181197
}
182198
}

‎src/test/ui/regions/regions-mock-codegen.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
// run-pass
22
#![allow(dead_code)]
33
#![allow(non_camel_case_types)]
4-
54
// pretty-expanded FIXME #23616
6-
75
#![feature(allocator_api)]
86

9-
use std::alloc::{AllocRef, Global, Layout, handle_alloc_error};
7+
use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout};
108
use std::ptr::NonNull;
119

1210
struct arena(());
1311

1412
struct Bcx<'a> {
15-
fcx: &'a Fcx<'a>
13+
fcx: &'a Fcx<'a>,
1614
}
1715

1816
struct Fcx<'a> {
1917
arena: &'a arena,
20-
ccx: &'a Ccx
18+
ccx: &'a Ccx,
2119
}
2220

2321
struct Ccx {
24-
x: isize
22+
x: isize,
2523
}
2624

2725
fn alloc(_bcx: &arena) -> &Bcx<'_> {
2826
unsafe {
2927
let layout = Layout::new::<Bcx>();
30-
let (ptr, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout));
28+
let (ptr, _) = Global
29+
.alloc(layout, AllocInit::Uninitialized)
30+
.unwrap_or_else(|_| handle_alloc_error(layout));
3131
&*(ptr.as_ptr() as *const _)
3232
}
3333
}

0 commit comments

Comments
 (0)
Please sign in to comment.