Skip to content

Commit e028687

Browse files
committed
Auto merge of #50144 - sfackler:oom-lang-item, r=alexcrichton
Replace {Alloc,GlobalAlloc}::oom with a lang item. The decision of what to do after an allocation fails is orthogonal to the decision of how to allocate the memory, so this PR splits them apart. `Alloc::oom` and `GlobalAlloc::oom` have been removed, and a lang item has been added: ```rust #[lang = "oom"] fn oom() -> !; ``` It is specifically a weak lang item, like panic_fmt, except that it is required when you depend on liballoc rather than libcore. libstd provides an implementation that aborts with the message `fatal runtime error: memory allocation failed`, matching the current behavior. The new implementation is also significantly simpler - it's "just another weak lang item". [RFC 2070](https://github.com/rust-lang/rfcs/blob/master/text/2070-panic-implementation.md) specifies a path towards stabilizing panic_fmt, so any complexities around stable weak lang item definition are already being solved. To bootstrap, oom silently aborts in stage0. alloc_system no longer has a bunch of code to print to stderr, and alloc_jemalloc no longer depends on alloc_system to pull in that code. One fun note: System's GlobalAlloc implementation didn't override the default implementation of oom, so it currently aborts silently! r? @alexcrichton
2 parents ff48277 + 5969712 commit e028687

File tree

23 files changed

+61
-177
lines changed

23 files changed

+61
-177
lines changed

src/Cargo.lock

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/liballoc/alloc.rs

+17-21
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ extern "Rust" {
4848
#[allocator]
4949
#[rustc_allocator_nounwind]
5050
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
51-
#[cold]
52-
#[rustc_allocator_nounwind]
53-
fn __rust_oom() -> !;
5451
#[rustc_allocator_nounwind]
5552
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
5653
#[rustc_allocator_nounwind]
@@ -107,16 +104,6 @@ unsafe impl GlobalAlloc for Global {
107104
let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0);
108105
ptr as *mut Opaque
109106
}
110-
111-
#[inline]
112-
fn oom(&self) -> ! {
113-
unsafe {
114-
#[cfg(not(stage0))]
115-
__rust_oom();
116-
#[cfg(stage0)]
117-
__rust_oom(&mut 0);
118-
}
119-
}
120107
}
121108

122109
unsafe impl Alloc for Global {
@@ -144,11 +131,6 @@ unsafe impl Alloc for Global {
144131
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
145132
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
146133
}
147-
148-
#[inline]
149-
fn oom(&mut self) -> ! {
150-
GlobalAlloc::oom(self)
151-
}
152134
}
153135

154136
/// The allocator for unique pointers.
@@ -165,7 +147,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
165147
if !ptr.is_null() {
166148
ptr as *mut u8
167149
} else {
168-
Global.oom()
150+
oom()
169151
}
170152
}
171153
}
@@ -182,19 +164,33 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
182164
}
183165
}
184166

167+
#[cfg(stage0)]
168+
pub fn oom() -> ! {
169+
unsafe { ::core::intrinsics::abort() }
170+
}
171+
172+
#[cfg(not(stage0))]
173+
pub fn oom() -> ! {
174+
extern {
175+
#[lang = "oom"]
176+
fn oom_impl() -> !;
177+
}
178+
unsafe { oom_impl() }
179+
}
180+
185181
#[cfg(test)]
186182
mod tests {
187183
extern crate test;
188184
use self::test::Bencher;
189185
use boxed::Box;
190-
use alloc::{Global, Alloc, Layout};
186+
use alloc::{Global, Alloc, Layout, oom};
191187

192188
#[test]
193189
fn allocate_zeroed() {
194190
unsafe {
195191
let layout = Layout::from_size_align(1024, 1).unwrap();
196192
let ptr = Global.alloc_zeroed(layout.clone())
197-
.unwrap_or_else(|_| Global.oom());
193+
.unwrap_or_else(|_| oom());
198194

199195
let mut i = ptr.cast::<u8>().as_ptr();
200196
let end = i.offset(layout.size() as isize);

src/liballoc/arc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use core::hash::{Hash, Hasher};
3131
use core::{isize, usize};
3232
use core::convert::From;
3333

34-
use alloc::{Global, Alloc, Layout, box_free};
34+
use alloc::{Global, Alloc, Layout, box_free, oom};
3535
use boxed::Box;
3636
use string::String;
3737
use vec::Vec;
@@ -553,7 +553,7 @@ impl<T: ?Sized> Arc<T> {
553553
let layout = Layout::for_value(&*fake_ptr);
554554

555555
let mem = Global.alloc(layout)
556-
.unwrap_or_else(|_| Global.oom());
556+
.unwrap_or_else(|_| oom());
557557

558558
// Initialize the real ArcInner
559559
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner<T>;

src/liballoc/heap.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ unsafe impl<T> Alloc for T where T: CoreAlloc {
5959
}
6060

6161
fn oom(&mut self, _: AllocErr) -> ! {
62-
CoreAlloc::oom(self)
62+
unsafe { ::core::intrinsics::abort() }
6363
}
6464

6565
fn usable_size(&self, layout: &Layout) -> (usize, usize) {

src/liballoc/raw_vec.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use core::ops::Drop;
1414
use core::ptr::{self, NonNull, Unique};
1515
use core::slice;
1616

17-
use alloc::{Alloc, Layout, Global};
17+
use alloc::{Alloc, Layout, Global, oom};
1818
use alloc::CollectionAllocErr;
1919
use alloc::CollectionAllocErr::*;
2020
use boxed::Box;
@@ -101,7 +101,7 @@ impl<T, A: Alloc> RawVec<T, A> {
101101
};
102102
match result {
103103
Ok(ptr) => ptr,
104-
Err(_) => a.oom(),
104+
Err(_) => oom(),
105105
}
106106
};
107107

@@ -316,7 +316,7 @@ impl<T, A: Alloc> RawVec<T, A> {
316316
new_size);
317317
match ptr_res {
318318
Ok(ptr) => (new_cap, ptr.cast().into()),
319-
Err(_) => self.a.oom(),
319+
Err(_) => oom(),
320320
}
321321
}
322322
None => {
@@ -325,7 +325,7 @@ impl<T, A: Alloc> RawVec<T, A> {
325325
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
326326
match self.a.alloc_array::<T>(new_cap) {
327327
Ok(ptr) => (new_cap, ptr.into()),
328-
Err(_) => self.a.oom(),
328+
Err(_) => oom(),
329329
}
330330
}
331331
};
@@ -442,7 +442,7 @@ impl<T, A: Alloc> RawVec<T, A> {
442442
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
443443
match self.try_reserve_exact(used_cap, needed_extra_cap) {
444444
Err(CapacityOverflow) => capacity_overflow(),
445-
Err(AllocErr) => self.a.oom(),
445+
Err(AllocErr) => oom(),
446446
Ok(()) => { /* yay */ }
447447
}
448448
}
@@ -552,7 +552,7 @@ impl<T, A: Alloc> RawVec<T, A> {
552552
pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
553553
match self.try_reserve(used_cap, needed_extra_cap) {
554554
Err(CapacityOverflow) => capacity_overflow(),
555-
Err(AllocErr) => self.a.oom(),
555+
Err(AllocErr) => oom(),
556556
Ok(()) => { /* yay */ }
557557
}
558558
}
@@ -667,7 +667,7 @@ impl<T, A: Alloc> RawVec<T, A> {
667667
old_layout,
668668
new_size) {
669669
Ok(p) => self.ptr = p.cast().into(),
670-
Err(_) => self.a.oom(),
670+
Err(_) => oom(),
671671
}
672672
}
673673
self.cap = amount;

src/liballoc/rc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ use core::ops::CoerceUnsized;
259259
use core::ptr::{self, NonNull};
260260
use core::convert::From;
261261

262-
use alloc::{Global, Alloc, Layout, Opaque, box_free};
262+
use alloc::{Global, Alloc, Layout, Opaque, box_free, oom};
263263
use string::String;
264264
use vec::Vec;
265265

@@ -668,7 +668,7 @@ impl<T: ?Sized> Rc<T> {
668668
let layout = Layout::for_value(&*fake_ptr);
669669

670670
let mem = Global.alloc(layout)
671-
.unwrap_or_else(|_| Global.oom());
671+
.unwrap_or_else(|_| oom());
672672

673673
// Initialize the real RcBox
674674
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>;

src/liballoc_jemalloc/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ test = false
1212
doc = false
1313

1414
[dependencies]
15-
alloc_system = { path = "../liballoc_system" }
1615
core = { path = "../libcore" }
1716
libc = { path = "../rustc/libc_shim" }
1817
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }

src/liballoc_jemalloc/lib.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
reason = "this library is unlikely to be stabilized in its current \
1515
form or name",
1616
issue = "27783")]
17-
#![feature(alloc_system)]
17+
#![feature(core_intrinsics)]
1818
#![feature(libc)]
1919
#![feature(linkage)]
2020
#![feature(staged_api)]
@@ -23,15 +23,12 @@
2323
#![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
2424
#![rustc_alloc_kind = "exe"]
2525

26-
extern crate alloc_system;
2726
extern crate libc;
2827

2928
#[cfg(not(dummy_jemalloc))]
3029
pub use contents::*;
3130
#[cfg(not(dummy_jemalloc))]
3231
mod contents {
33-
use core::alloc::GlobalAlloc;
34-
use alloc_system::System;
3532
use libc::{c_int, c_void, size_t};
3633

3734
// Note that the symbols here are prefixed by default on macOS and Windows (we
@@ -100,10 +97,11 @@ mod contents {
10097
ptr
10198
}
10299

100+
#[cfg(stage0)]
103101
#[no_mangle]
104102
#[rustc_std_internal_symbol]
105103
pub unsafe extern fn __rde_oom() -> ! {
106-
System.oom()
104+
::core::intrinsics::abort();
107105
}
108106

109107
#[no_mangle]

src/liballoc_system/lib.rs

-70
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ unsafe impl Alloc for System {
7171
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
7272
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
7373
}
74-
75-
#[inline]
76-
fn oom(&mut self) -> ! {
77-
::oom()
78-
}
7974
}
8075

8176
#[cfg(stage0)]
@@ -103,11 +98,6 @@ unsafe impl<'a> Alloc for &'a System {
10398
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
10499
NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
105100
}
106-
107-
#[inline]
108-
fn oom(&mut self) -> ! {
109-
::oom()
110-
}
111101
}
112102

113103
#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
@@ -366,63 +356,3 @@ mod platform {
366356
}
367357
}
368358
}
369-
370-
#[inline]
371-
fn oom() -> ! {
372-
write_to_stderr("fatal runtime error: memory allocation failed");
373-
unsafe {
374-
::core::intrinsics::abort();
375-
}
376-
}
377-
378-
#[cfg(any(unix, target_os = "redox"))]
379-
#[inline]
380-
fn write_to_stderr(s: &str) {
381-
extern crate libc;
382-
383-
unsafe {
384-
libc::write(libc::STDERR_FILENO,
385-
s.as_ptr() as *const libc::c_void,
386-
s.len());
387-
}
388-
}
389-
390-
#[cfg(windows)]
391-
#[inline]
392-
fn write_to_stderr(s: &str) {
393-
use core::ptr;
394-
395-
type LPVOID = *mut u8;
396-
type HANDLE = LPVOID;
397-
type DWORD = u32;
398-
type BOOL = i32;
399-
type LPDWORD = *mut DWORD;
400-
type LPOVERLAPPED = *mut u8;
401-
402-
const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
403-
404-
extern "system" {
405-
fn WriteFile(hFile: HANDLE,
406-
lpBuffer: LPVOID,
407-
nNumberOfBytesToWrite: DWORD,
408-
lpNumberOfBytesWritten: LPDWORD,
409-
lpOverlapped: LPOVERLAPPED)
410-
-> BOOL;
411-
fn GetStdHandle(which: DWORD) -> HANDLE;
412-
}
413-
414-
unsafe {
415-
// WriteFile silently fails if it is passed an invalid
416-
// handle, so there is no need to check the result of
417-
// GetStdHandle.
418-
WriteFile(GetStdHandle(STD_ERROR_HANDLE),
419-
s.as_ptr() as LPVOID,
420-
s.len() as DWORD,
421-
ptr::null_mut(),
422-
ptr::null_mut());
423-
}
424-
}
425-
426-
#[cfg(not(any(windows, unix, target_os = "redox")))]
427-
#[inline]
428-
fn write_to_stderr(_: &str) {}

src/libcore/alloc.rs

-37
Original file line numberDiff line numberDiff line change
@@ -451,17 +451,6 @@ pub unsafe trait GlobalAlloc {
451451
}
452452
new_ptr
453453
}
454-
455-
/// Aborts the thread or process, optionally performing
456-
/// cleanup or logging diagnostic information before panicking or
457-
/// aborting.
458-
///
459-
/// `oom` is meant to be used by clients unable to cope with an
460-
/// unsatisfied allocation request, and wish to abandon
461-
/// computation rather than attempt to recover locally.
462-
fn oom(&self) -> ! {
463-
unsafe { ::intrinsics::abort() }
464-
}
465454
}
466455

467456
/// An implementation of `Alloc` can allocate, reallocate, and
@@ -614,32 +603,6 @@ pub unsafe trait Alloc {
614603
/// to allocate that block of memory.
615604
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout);
616605

617-
/// Allocator-specific method for signaling an out-of-memory
618-
/// condition.
619-
///
620-
/// `oom` aborts the thread or process, optionally performing
621-
/// cleanup or logging diagnostic information before panicking or
622-
/// aborting.
623-
///
624-
/// `oom` is meant to be used by clients unable to cope with an
625-
/// unsatisfied allocation request, and wish to abandon
626-
/// computation rather than attempt to recover locally.
627-
///
628-
/// Implementations of the `oom` method are discouraged from
629-
/// infinitely regressing in nested calls to `oom`. In
630-
/// practice this means implementors should eschew allocating,
631-
/// especially from `self` (directly or indirectly).
632-
///
633-
/// Implementations of the allocation and reallocation methods
634-
/// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from
635-
/// panicking (or aborting) in the event of memory exhaustion;
636-
/// instead they should return an appropriate error from the
637-
/// invoked method, and let the client decide whether to invoke
638-
/// this `oom` method in response.
639-
fn oom(&mut self) -> ! {
640-
unsafe { ::intrinsics::abort() }
641-
}
642-
643606
// == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS ==
644607
// usable_size
645608

src/librustc/middle/lang_items.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ language_item_table! {
303303

304304
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
305305
BoxFreeFnLangItem, "box_free", box_free_fn;
306-
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
306+
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
307+
OomLangItem, "oom", oom;
307308

308309
StartFnLangItem, "start", start_fn;
309310

0 commit comments

Comments
 (0)