-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Make handle_alloc_error
default to panic (for no_std + liballoc)
#76448
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,8 @@ extern "Rust" { | |
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; | ||
#[rustc_allocator_nounwind] | ||
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; | ||
#[rustc_allocator_nounwind] | ||
fn __rust_alloc_error_handler(size: usize, align: usize) -> !; | ||
} | ||
|
||
/// The global memory allocator. | ||
|
@@ -334,6 +336,24 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) { | |
/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html | ||
/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html | ||
#[stable(feature = "global_alloc", since = "1.28.0")] | ||
#[cfg(not(any(test, bootstrap)))] | ||
#[rustc_allocator_nounwind] | ||
pub fn handle_alloc_error(layout: Layout) -> ! { | ||
unsafe { | ||
__rust_alloc_error_handler(layout.size(), layout.align()); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For tests you can just do: pub use std::alloc::handle_alloc_error; This works since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, changed |
||
|
||
// For alloc test `std::alloc::handle_alloc_error` can be used directly. | ||
#[cfg(test)] | ||
pub use std::alloc::handle_alloc_error; | ||
|
||
// In stage0 (bootstrap) `__rust_alloc_error_handler`, | ||
// might not be generated yet, because an old compiler is used, | ||
// so use the old direct call. | ||
#[cfg(all(bootstrap, not(test)))] | ||
#[stable(feature = "global_alloc", since = "1.28.0")] | ||
#[doc(hidden)] | ||
#[rustc_allocator_nounwind] | ||
pub fn handle_alloc_error(layout: Layout) -> ! { | ||
extern "Rust" { | ||
|
@@ -342,3 +362,30 @@ pub fn handle_alloc_error(layout: Layout) -> ! { | |
} | ||
unsafe { oom_impl(layout) } | ||
} | ||
|
||
#[cfg(not(any(test, bootstrap)))] | ||
#[doc(hidden)] | ||
#[allow(unused_attributes)] | ||
#[unstable(feature = "alloc_internals", issue = "none")] | ||
pub mod __default_lib_allocator { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this module name, given that this is not an allocator, but an alloc-error handler. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true |
||
use crate::alloc::Layout; | ||
|
||
// called via generated `__rust_alloc_error_handler` | ||
|
||
// if there is no `#[alloc_error_handler]` | ||
#[rustc_std_internal_symbol] | ||
pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! { | ||
panic!("memory allocation of {} bytes failed", size) | ||
} | ||
|
||
// if there is a `#[alloc_error_handler]` | ||
#[rustc_std_internal_symbol] | ||
pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nothing like this exists for the allocator, right? There the generated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah no, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be removed, if I just didn't know, how to generate a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the symmetric thing to do (when compared with It is just somewhat dissatisfying that the very same problem is solved three times in slightly different ways with various amounts of code sharing (global allocator, alloc error handler, panic handler). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree, but to implement it efficiently, I lack the expertise to redirect it via the rust ABI. |
||
let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; | ||
extern "Rust" { | ||
#[lang = "oom"] | ||
fn oom_impl(layout: Layout) -> !; | ||
} | ||
unsafe { oom_impl(layout) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean that, unlike before, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I blindly copied There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, or the other way round, I might have missed it. |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// run-pass | ||
// ignore-android no libc | ||
// ignore-cloudabi no libc | ||
// ignore-emscripten no libc | ||
// ignore-sgx no libc | ||
// ignore-wasm32 no libc | ||
// only-linux | ||
// compile-flags:-C panic=abort | ||
// aux-build:helper.rs | ||
|
||
#![feature(start, rustc_private, new_uninit, panic_info_message)] | ||
#![feature(alloc_error_handler)] | ||
#![no_std] | ||
|
||
extern crate alloc; | ||
extern crate libc; | ||
|
||
// ARM targets need these symbols | ||
#[no_mangle] | ||
pub fn __aeabi_unwind_cpp_pr0() {} | ||
|
||
#[no_mangle] | ||
pub fn __aeabi_unwind_cpp_pr1() {} | ||
|
||
use core::ptr::null_mut; | ||
use core::alloc::{GlobalAlloc, Layout}; | ||
use alloc::boxed::Box; | ||
|
||
extern crate helper; | ||
|
||
struct MyAllocator; | ||
|
||
#[alloc_error_handler] | ||
fn my_oom(layout: Layout) -> ! | ||
{ | ||
use alloc::fmt::write; | ||
unsafe { | ||
let size = layout.size(); | ||
let mut s = alloc::string::String::new(); | ||
write(&mut s, format_args!("My OOM: failed to allocate {} bytes!\n", size)).unwrap(); | ||
let s = s.as_str(); | ||
libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len()); | ||
libc::exit(0) | ||
} | ||
} | ||
|
||
unsafe impl GlobalAlloc for MyAllocator { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
if layout.size() < 4096 { | ||
libc::malloc(layout.size()) as _ | ||
} else { | ||
null_mut() | ||
} | ||
} | ||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} | ||
} | ||
|
||
#[global_allocator] | ||
static A: MyAllocator = MyAllocator; | ||
|
||
#[panic_handler] | ||
fn panic(panic_info: &core::panic::PanicInfo) -> ! { | ||
unsafe { | ||
if let Some(s) = panic_info.payload().downcast_ref::<&str>() { | ||
const PSTR: &str = "panic occurred: "; | ||
const CR: &str = "\n"; | ||
libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len()); | ||
libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len()); | ||
libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len()); | ||
} | ||
if let Some(args) = panic_info.message() { | ||
let mut s = alloc::string::String::new(); | ||
alloc::fmt::write(&mut s, *args).unwrap(); | ||
let s = s.as_str(); | ||
const PSTR: &str = "panic occurred: "; | ||
const CR: &str = "\n"; | ||
libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len()); | ||
libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len()); | ||
libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len()); | ||
} else { | ||
const PSTR: &str = "panic occurred\n"; | ||
libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len()); | ||
} | ||
libc::exit(1) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
struct Page([[u64; 32]; 16]); | ||
|
||
#[start] | ||
pub fn main(_argc: isize, _argv: *const *const u8) -> isize { | ||
let zero = Box::<Page>::new_zeroed(); | ||
let zero = unsafe { zero.assume_init() }; | ||
helper::work_with(&zero); | ||
1 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// run-pass | ||
// ignore-android no libc | ||
// ignore-cloudabi no libc | ||
// ignore-emscripten no libc | ||
// ignore-sgx no libc | ||
// ignore-wasm32 no libc | ||
// only-linux | ||
// compile-flags:-C panic=abort | ||
// aux-build:helper.rs | ||
// gate-test-default_alloc_error_handler | ||
|
||
#![feature(start, rustc_private, new_uninit, panic_info_message)] | ||
#![feature(default_alloc_error_handler)] | ||
#![no_std] | ||
|
||
extern crate alloc; | ||
extern crate libc; | ||
|
||
// ARM targets need these symbols | ||
#[no_mangle] | ||
pub fn __aeabi_unwind_cpp_pr0() {} | ||
|
||
#[no_mangle] | ||
pub fn __aeabi_unwind_cpp_pr1() {} | ||
|
||
use alloc::boxed::Box; | ||
use core::alloc::{GlobalAlloc, Layout}; | ||
use core::ptr::null_mut; | ||
|
||
extern crate helper; | ||
|
||
struct MyAllocator; | ||
|
||
unsafe impl GlobalAlloc for MyAllocator { | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
if layout.size() < 4096 { | ||
libc::malloc(layout.size()) as _ | ||
} else { | ||
null_mut() | ||
} | ||
} | ||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} | ||
} | ||
|
||
#[global_allocator] | ||
static A: MyAllocator = MyAllocator; | ||
|
||
#[panic_handler] | ||
fn panic(panic_info: &core::panic::PanicInfo) -> ! { | ||
unsafe { | ||
if let Some(s) = panic_info.payload().downcast_ref::<&str>() { | ||
const PSTR: &str = "panic occurred: "; | ||
const CR: &str = "\n"; | ||
libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len()); | ||
libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len()); | ||
libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len()); | ||
} | ||
if let Some(args) = panic_info.message() { | ||
let mut s = alloc::string::String::new(); | ||
alloc::fmt::write(&mut s, *args).unwrap(); | ||
let s = s.as_str(); | ||
const PSTR: &str = "panic occurred: "; | ||
const CR: &str = "\n"; | ||
libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len()); | ||
libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len()); | ||
libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len()); | ||
} else { | ||
const PSTR: &str = "panic occurred\n"; | ||
libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len()); | ||
} | ||
libc::exit(0) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
struct Page([[u64; 32]; 16]); | ||
|
||
#[start] | ||
pub fn main(_argc: isize, _argv: *const *const u8) -> isize { | ||
let zero = Box::<Page>::new_zeroed(); | ||
let zero = unsafe { zero.assume_init() }; | ||
helper::work_with(&zero); | ||
1 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
error: `#[alloc_error_handler]` function required, but not found | ||
error: `#[alloc_error_handler]` function required, but not found. | ||
|
||
note: Use `#![feature(default_alloc_error_handler)]` for a default error handler. | ||
|
||
error: aborting due to previous error | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason you duplicated this code rather than adding a new entry to
ALLOCATOR_METHODS
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bjorn3
ALLOCATOR_METHODS
is also used elsewhere to build other stuff, which I didn't want to clobbername
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bjorn3 feel free to refactor the stuff without side effects