From 116f4ae171e292423304ee6842a11c48a4fff5ba Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:44:01 +0000 Subject: [PATCH] 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. --- compiler/rustc_ast/src/expand/allocator.rs | 8 +----- .../src/alloc_error_handler.rs | 5 ++-- .../rustc_codegen_cranelift/src/allocator.rs | 28 ++++++++++--------- compiler/rustc_codegen_gcc/src/allocator.rs | 24 ++++++++-------- compiler/rustc_codegen_llvm/src/allocator.rs | 28 ++++++++++--------- .../src/back/symbol_export.rs | 6 ++-- compiler/rustc_metadata/src/creader.rs | 24 ++++++++-------- library/alloc/src/alloc.rs | 4 +-- library/std/src/alloc.rs | 7 +++-- src/tools/miri/src/shims/foreign_items.rs | 17 ++++++----- .../fail/alloc/alloc_error_handler.stderr | 2 +- .../alloc/alloc_error_handler_custom.stderr | 2 +- .../alloc/alloc_error_handler_no_std.stderr | 2 +- tests/run-make/bin-emit-no-symbols/rmake.rs | 2 +- tests/ui/sanitizer/dataflow-abilist.txt | 10 ------- 15 files changed, 83 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index 7dee2ed17b4b..a3f9ddb154f7 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -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 { diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 35ef6be095e9..40946f3b2791 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -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, diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 04f1129d87c1..9533f870434a 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -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 { diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 2a95a7368aac..3f99612fcdb0 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -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, diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 486ee817a1c7..b645db3f4a8b 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -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( diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b49e67217fb0..5bc18e2d7f8b 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -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), ]) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 7650acbd292d..87d64817466d 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -6,7 +6,7 @@ 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 @@ fn inject_allocator_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { } 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 diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 65c8206e9d46..39450f69ce30 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -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. diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 1d61630269ac..daa25c5a50dd 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -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()); } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index eca8cccf5efc..467ac2805fe5 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -3,7 +3,7 @@ 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 @@ fn emulate_foreign_item( // 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 @@ fn emulate_foreign_item( "`__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)); + } } _ => {} } diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index bbf5d14a98a1..7f7fc63ac0dd 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -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` diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr index a2a4be30eca4..f8a96758aa2d 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr @@ -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] diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr index 45ba366acae3..488b1d879e87 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr @@ -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` diff --git a/tests/run-make/bin-emit-no-symbols/rmake.rs b/tests/run-make/bin-emit-no-symbols/rmake.rs index 2faeb20025bb..0822bd6dfd6a 100644 --- a/tests/run-make/bin-emit-no-symbols/rmake.rs +++ b/tests/run-make/bin-emit-no-symbols/rmake.rs @@ -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"); } diff --git a/tests/ui/sanitizer/dataflow-abilist.txt b/tests/ui/sanitizer/dataflow-abilist.txt index 3d32397a175d..b6fdfe3cbf6e 100644 --- a/tests/ui/sanitizer/dataflow-abilist.txt +++ b/tests/ui/sanitizer/dataflow-abilist.txt @@ -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