Support #[alloc_error_handler] without the allocator shim
Currently it is possible to avoid linking the allocator shim when __rust_no_alloc_shim_is_unstable_v2 is defined when linking rlibs directly as some build systems need. However this requires liballoc to be compiled with --cfg no_global_oom_handling, which places huge restrictions on what functions you can call and makes it impossible to use libstd. Or alternatively you have to define __rust_alloc_error_handler and (when using libstd) __rust_alloc_error_handler_should_panic using #[rustc_std_internal_symbol]. With this commit you can either use libstd and define __rust_alloc_error_handler_should_panic or not use libstd and use #[alloc_error_handler] instead. Both options are still unstable though. Eventually the alloc_error_handler may either be removed entirely (though the PR for that has been stale for years now) or we may start using weak symbols for it instead. For the latter case this commit is a prerequisite anyway.
This commit is contained in:
parent
f47c48048d
commit
116f4ae171
15 changed files with 83 additions and 86 deletions
|
|
@ -15,13 +15,7 @@ pub fn default_fn_name(base: Symbol) -> String {
|
|||
format!("__rdl_{base}")
|
||||
}
|
||||
|
||||
pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str {
|
||||
match alloc_error_handler_kind {
|
||||
AllocatorKind::Global => "__rg_oom",
|
||||
AllocatorKind::Default => "__rdl_oom",
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALLOC_ERROR_HANDLER: Symbol = sym::alloc_error_handler;
|
||||
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2";
|
||||
|
||||
pub enum AllocatorTy {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, global_fn_name};
|
||||
use rustc_ast::{
|
||||
self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind,
|
||||
};
|
||||
|
|
@ -55,7 +56,7 @@ pub(crate) fn expand(
|
|||
}
|
||||
|
||||
// #[rustc_std_internal_symbol]
|
||||
// unsafe fn __rg_oom(size: usize, align: usize) -> ! {
|
||||
// unsafe fn __rust_alloc_error_handler(size: usize, align: usize) -> ! {
|
||||
// handler(core::alloc::Layout::from_size_align_unchecked(size, align))
|
||||
// }
|
||||
fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt {
|
||||
|
|
@ -84,7 +85,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
|
|||
let kind = ItemKind::Fn(Box::new(Fn {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
sig,
|
||||
ident: Ident::from_str_and_span("__rg_oom", span),
|
||||
ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
|
||||
generics: Generics::default(),
|
||||
contract: None,
|
||||
body,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use rustc_ast::expand::allocator::{
|
||||
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||
alloc_error_handler_name, default_fn_name, global_fn_name,
|
||||
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||
default_fn_name, global_fn_name,
|
||||
};
|
||||
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
|
||||
use rustc_session::config::OomStrategy;
|
||||
|
|
@ -72,17 +72,19 @@ fn codegen_inner(
|
|||
}
|
||||
}
|
||||
|
||||
let sig = Signature {
|
||||
call_conv: module.target_config().default_call_conv,
|
||||
params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
|
||||
returns: vec![],
|
||||
};
|
||||
crate::common::create_wrapper_function(
|
||||
module,
|
||||
sig,
|
||||
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
|
||||
&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)),
|
||||
);
|
||||
if alloc_error_handler_kind == AllocatorKind::Default {
|
||||
let sig = Signature {
|
||||
call_conv: module.target_config().default_call_conv,
|
||||
params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
|
||||
returns: vec![],
|
||||
};
|
||||
crate::common::create_wrapper_function(
|
||||
module,
|
||||
sig,
|
||||
&mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)),
|
||||
&mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER)),
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let sig = Signature {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
use gccjit::FnAttribute;
|
||||
use gccjit::{Context, FunctionType, RValue, ToRValue, Type};
|
||||
use rustc_ast::expand::allocator::{
|
||||
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||
alloc_error_handler_name, default_fn_name, global_fn_name,
|
||||
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||
default_fn_name, global_fn_name,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -61,15 +61,17 @@ pub(crate) unsafe fn codegen(
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(bjorn3): Add noreturn attribute
|
||||
create_wrapper_function(
|
||||
tcx,
|
||||
context,
|
||||
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
|
||||
Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
|
||||
&[usize, usize],
|
||||
None,
|
||||
);
|
||||
if alloc_error_handler_kind == AllocatorKind::Default {
|
||||
// FIXME(bjorn3): Add noreturn attribute
|
||||
create_wrapper_function(
|
||||
tcx,
|
||||
context,
|
||||
&mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)),
|
||||
Some(&mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER))),
|
||||
&[usize, usize],
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
create_const_value_function(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use libc::c_uint;
|
||||
use rustc_ast::expand::allocator::{
|
||||
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||
alloc_error_handler_name, default_fn_name, global_fn_name,
|
||||
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||
default_fn_name, global_fn_name,
|
||||
};
|
||||
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
|
||||
use rustc_middle::bug;
|
||||
|
|
@ -83,17 +83,19 @@ pub(crate) unsafe fn codegen(
|
|||
}
|
||||
}
|
||||
|
||||
// rust alloc error handler
|
||||
create_wrapper_function(
|
||||
tcx,
|
||||
&cx,
|
||||
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
|
||||
Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
|
||||
&[usize, usize], // size, align
|
||||
None,
|
||||
true,
|
||||
&CodegenFnAttrs::new(),
|
||||
);
|
||||
if alloc_error_handler_kind == AllocatorKind::Default {
|
||||
// rust alloc error handler
|
||||
create_wrapper_function(
|
||||
tcx,
|
||||
&cx,
|
||||
&mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)),
|
||||
Some(&mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER))),
|
||||
&[usize, usize], // size, align
|
||||
None,
|
||||
true,
|
||||
&CodegenFnAttrs::new(),
|
||||
);
|
||||
}
|
||||
|
||||
// __rust_alloc_error_handler_should_panic_v2
|
||||
create_const_value_function(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::collections::hash_map::Entry::*;
|
||||
|
||||
use rustc_abi::{CanonAbi, X86Call};
|
||||
use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name};
|
||||
use rustc_ast::expand::allocator::{
|
||||
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name,
|
||||
};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId};
|
||||
|
|
@ -498,7 +500,7 @@ pub(crate) fn allocator_shim_symbols(
|
|||
.iter()
|
||||
.map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
|
||||
.chain([
|
||||
mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
|
||||
mangle_internal_symbol(tcx, global_fn_name(ALLOC_ERROR_HANDLER).as_str()),
|
||||
mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
|
||||
mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
|
||||
])
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::str::FromStr;
|
|||
use std::time::Duration;
|
||||
use std::{cmp, env, iter};
|
||||
|
||||
use rustc_ast::expand::allocator::{AllocatorKind, alloc_error_handler_name, global_fn_name};
|
||||
use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, AllocatorKind, global_fn_name};
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::owned_slice::OwnedSlice;
|
||||
|
|
@ -1087,17 +1087,17 @@ impl CStore {
|
|||
}
|
||||
spans => !spans.is_empty(),
|
||||
};
|
||||
self.has_alloc_error_handler = match &*fn_spans(
|
||||
krate,
|
||||
Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)),
|
||||
) {
|
||||
[span1, span2, ..] => {
|
||||
tcx.dcx()
|
||||
.emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
|
||||
true
|
||||
}
|
||||
spans => !spans.is_empty(),
|
||||
};
|
||||
self.has_alloc_error_handler =
|
||||
match &*fn_spans(krate, Symbol::intern(&global_fn_name(ALLOC_ERROR_HANDLER))) {
|
||||
[span1, span2, ..] => {
|
||||
tcx.dcx().emit_err(errors::NoMultipleAllocErrorHandler {
|
||||
span2: *span2,
|
||||
span1: *span1,
|
||||
});
|
||||
true
|
||||
}
|
||||
spans => !spans.is_empty(),
|
||||
};
|
||||
|
||||
// Check to see if we actually need an allocator. This desire comes
|
||||
// about through the `#![needs_allocator]` attribute and is typically
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
|||
unsafe extern "Rust" {
|
||||
// This is the magic symbol to call the global alloc error handler. rustc generates
|
||||
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
|
||||
// default implementations below (`__rdl_oom`) otherwise.
|
||||
// default implementations below (`__rdl_alloc_error_handler`) otherwise.
|
||||
#[rustc_std_internal_symbol]
|
||||
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
|
||||
}
|
||||
|
|
@ -425,7 +425,7 @@ pub mod __alloc_error_handler {
|
|||
// called via generated `__rust_alloc_error_handler` if there is no
|
||||
// `#[alloc_error_handler]`.
|
||||
#[rustc_std_internal_symbol]
|
||||
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
|
||||
pub unsafe fn __rdl_alloc_error_handler(size: usize, _align: usize) -> ! {
|
||||
unsafe extern "Rust" {
|
||||
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
|
||||
// Its value depends on the -Zoom={panic,abort} compiler option.
|
||||
|
|
|
|||
|
|
@ -358,9 +358,10 @@ fn default_alloc_error_hook(layout: Layout) {
|
|||
// This is the default path taken on OOM, and the only path taken on stable with std.
|
||||
// Crucially, it does *not* call any user-defined code, and therefore users do not have to
|
||||
// worry about allocation failure causing reentrancy issues. That makes it different from
|
||||
// the default `__rdl_oom` defined in alloc (i.e., the default alloc error handler that is
|
||||
// called when there is no `#[alloc_error_handler]`), which triggers a regular panic and
|
||||
// thus can invoke a user-defined panic hook, executing arbitrary user-defined code.
|
||||
// the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error
|
||||
// handler that is called when there is no `#[alloc_error_handler]`), which triggers a
|
||||
// regular panic and thus can invoke a user-defined panic hook, executing arbitrary
|
||||
// user-defined code.
|
||||
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::io::Write;
|
|||
use std::path::Path;
|
||||
|
||||
use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size};
|
||||
use rustc_ast::expand::allocator::alloc_error_handler_name;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_hir::attrs::Linkage;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
|
|
@ -51,6 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// Some shims forward to other MIR bodies.
|
||||
match link_name.as_str() {
|
||||
// FIXME should use global_fn_name, but mangle_internal_symbol requires a static str.
|
||||
name if name == this.mangle_internal_symbol("__rust_alloc_error_handler") => {
|
||||
// Forward to the right symbol that implements this function.
|
||||
let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else {
|
||||
|
|
@ -59,12 +60,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
"`__rust_alloc_error_handler` cannot be called when no alloc error handler is set"
|
||||
);
|
||||
};
|
||||
let name = Symbol::intern(
|
||||
this.mangle_internal_symbol(alloc_error_handler_name(handler_kind)),
|
||||
);
|
||||
let handler =
|
||||
this.lookup_exported_symbol(name)?.expect("missing alloc error handler symbol");
|
||||
return interp_ok(Some(handler));
|
||||
if handler_kind == AllocatorKind::Default {
|
||||
let name =
|
||||
Symbol::intern(this.mangle_internal_symbol("__rdl_alloc_error_handler"));
|
||||
let handler = this
|
||||
.lookup_exported_symbol(name)?
|
||||
.expect("missing alloc error handler symbol");
|
||||
return interp_ok(Some(handler));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ LL | crate::process::abort()
|
|||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::alloc::rust_oom` at RUSTLIB/std/src/alloc.rs:LL:CC
|
||||
= note: inside `std::alloc::_::__rg_oom` at RUSTLIB/std/src/alloc.rs:LL:CC
|
||||
= note: inside `std::alloc::_::__rust_alloc_error_handler` at RUSTLIB/std/src/alloc.rs:LL:CC
|
||||
= note: inside `std::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||
= note: inside `std::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ LL | core::intrinsics::abort();
|
|||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `alloc_error_handler` at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC
|
||||
note: inside `_::__rg_oom`
|
||||
note: inside `_::__rust_alloc_error_handler`
|
||||
--> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC
|
||||
|
|
||||
LL | #[alloc_error_handler]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ LL | core::intrinsics::abort();
|
|||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `panic_handler` at tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC
|
||||
= note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||
= note: inside `alloc::alloc::__alloc_error_handler::__rdl_alloc_error_handler` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||
= note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||
= note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||
note: inside `miri_start`
|
||||
|
|
|
|||
|
|
@ -14,5 +14,5 @@ fn main() {
|
|||
let out = llvm_readobj().input("app.o").arg("--symbols").run();
|
||||
out.assert_stdout_contains("rust_begin_unwind");
|
||||
out.assert_stdout_contains("rust_eh_personality");
|
||||
out.assert_stdout_contains("__rg_oom");
|
||||
out.assert_stdout_contains("__rust_alloc_error_handler");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -490,16 +490,6 @@ fun:__dfso_*=uninstrumented
|
|||
fun:__dfso_*=discard
|
||||
|
||||
# Rust functions.
|
||||
fun:__rdl_alloc=uninstrumented
|
||||
fun:__rdl_alloc_zeroed=uninstrumented
|
||||
fun:__rdl_dealloc=uninstrumented
|
||||
fun:__rdl_realloc=uninstrumented
|
||||
fun:__rg_oom=uninstrumented
|
||||
fun:__rust_alloc=uninstrumented
|
||||
fun:__rust_alloc_error_handler=uninstrumented
|
||||
fun:__rust_alloc_zeroed=uninstrumented
|
||||
fun:__rust_dealloc=uninstrumented
|
||||
fun:__rust_realloc=uninstrumented
|
||||
fun:_ZN4core*=uninstrumented
|
||||
fun:_ZN3std*=uninstrumented
|
||||
fun:rust_eh_personality=uninstrumented
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue