Rollup merge of #110782 - matthiaskrgr:revert_panic_oom, r=Amanieu
Revert panic oom This temporarily reverts https://github.com/rust-lang/rust/pull/109507 until https://github.com/rust-lang/rust/issues/110771 is addressed r? `@Amanieu`
This commit is contained in:
commit
2d72abc8f2
@ -4,6 +4,8 @@ builtin_macros_requires_cfg_pattern =
|
||||
|
||||
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
|
||||
|
||||
builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
|
||||
|
||||
builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument
|
||||
.label = boolean expression required
|
||||
|
||||
|
97
compiler/rustc_builtin_macros/src/alloc_error_handler.rs
Normal file
97
compiler/rustc_builtin_macros/src/alloc_error_handler.rs
Normal file
@ -0,0 +1,97 @@
|
||||
use crate::errors;
|
||||
use crate::util::check_builtin_macro_attribute;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
|
||||
use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
pub fn expand(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
_span: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: Annotatable,
|
||||
) -> Vec<Annotatable> {
|
||||
check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
|
||||
|
||||
let orig_item = item.clone();
|
||||
|
||||
// Allow using `#[alloc_error_handler]` on an item statement
|
||||
// FIXME - if we get deref patterns, use them to reduce duplication here
|
||||
let (item, is_stmt, sig_span) =
|
||||
if let Annotatable::Item(item) = &item
|
||||
&& let ItemKind::Fn(fn_kind) = &item.kind
|
||||
{
|
||||
(item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||
} else if let Annotatable::Stmt(stmt) = &item
|
||||
&& let StmtKind::Item(item) = &stmt.kind
|
||||
&& let ItemKind::Fn(fn_kind) = &item.kind
|
||||
{
|
||||
(item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
|
||||
} else {
|
||||
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() });
|
||||
return vec![orig_item];
|
||||
};
|
||||
|
||||
// Generate a bunch of new items using the AllocFnFactory
|
||||
let span = ecx.with_def_site_ctxt(item.span);
|
||||
|
||||
// Generate item statements for the allocator methods.
|
||||
let stmts = thin_vec![generate_handler(ecx, item.ident, span, sig_span)];
|
||||
|
||||
// Generate anonymous constant serving as container for the allocator methods.
|
||||
let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new()));
|
||||
let const_body = ecx.expr_block(ecx.block(span, stmts));
|
||||
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
|
||||
let const_item = if is_stmt {
|
||||
Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
|
||||
} else {
|
||||
Annotatable::Item(const_item)
|
||||
};
|
||||
|
||||
// Return the original item and the new methods.
|
||||
vec![orig_item, const_item]
|
||||
}
|
||||
|
||||
// #[rustc_std_internal_symbol]
|
||||
// unsafe fn __rg_oom(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 {
|
||||
let usize = cx.path_ident(span, Ident::new(sym::usize, span));
|
||||
let ty_usize = cx.ty_path(usize);
|
||||
let size = Ident::from_str_and_span("size", span);
|
||||
let align = Ident::from_str_and_span("align", span);
|
||||
|
||||
let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
|
||||
let layout_new = cx.expr_path(cx.path(span, layout_new));
|
||||
let layout = cx.expr_call(
|
||||
span,
|
||||
layout_new,
|
||||
thin_vec![cx.expr_ident(span, size), cx.expr_ident(span, align)],
|
||||
);
|
||||
|
||||
let call = cx.expr_call_ident(sig_span, handler, thin_vec![layout]);
|
||||
|
||||
let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
|
||||
let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
|
||||
let decl = cx.fn_decl(params, never);
|
||||
let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
|
||||
let sig = FnSig { decl, header, span: span };
|
||||
|
||||
let body = Some(cx.block_expr(call));
|
||||
let kind = ItemKind::Fn(Box::new(Fn {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
sig,
|
||||
generics: Generics::default(),
|
||||
body,
|
||||
}));
|
||||
|
||||
let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)];
|
||||
|
||||
let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind);
|
||||
cx.stmt_item(sig_span, item)
|
||||
}
|
@ -19,6 +19,13 @@ pub(crate) struct OneCfgPattern {
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_alloc_error_must_be_fn)]
|
||||
pub(crate) struct AllocErrorMustBeFn {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_assert_requires_boolean)]
|
||||
pub(crate) struct AssertRequiresBoolean {
|
||||
|
@ -27,6 +27,7 @@ use rustc_expand::proc_macro::BangProcMacro;
|
||||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
mod alloc_error_handler;
|
||||
mod assert;
|
||||
mod cfg;
|
||||
mod cfg_accessible;
|
||||
@ -103,6 +104,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
||||
}
|
||||
|
||||
register_attr! {
|
||||
alloc_error_handler: alloc_error_handler::expand,
|
||||
bench: test::expand_bench,
|
||||
cfg_accessible: cfg_accessible::Expander,
|
||||
cfg_eval: cfg_eval::expand,
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![feature(start, core_intrinsics)]
|
||||
#![feature(start, core_intrinsics, alloc_error_handler)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
@ -22,6 +22,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
let world: Box<&str> = Box::new("Hello World!\0");
|
||||
|
@ -6,6 +6,7 @@ use crate::prelude::*;
|
||||
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
|
||||
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
|
||||
use rustc_session::config::OomStrategy;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
/// Returns whether an allocator shim was created
|
||||
pub(crate) fn codegen(
|
||||
@ -14,7 +15,13 @@ pub(crate) fn codegen(
|
||||
unwind_context: &mut UnwindContext,
|
||||
) -> bool {
|
||||
let Some(kind) = allocator_kind_for_codegen(tcx) else { return false };
|
||||
codegen_inner(module, unwind_context, kind, tcx.sess.opts.unstable_opts.oom);
|
||||
codegen_inner(
|
||||
module,
|
||||
unwind_context,
|
||||
kind,
|
||||
tcx.alloc_error_handler_kind(()).unwrap(),
|
||||
tcx.sess.opts.unstable_opts.oom,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
@ -22,6 +29,7 @@ fn codegen_inner(
|
||||
module: &mut impl Module,
|
||||
unwind_context: &mut UnwindContext,
|
||||
kind: AllocatorKind,
|
||||
alloc_error_handler_kind: AllocatorKind,
|
||||
oom_strategy: OomStrategy,
|
||||
) {
|
||||
let usize_ty = module.target_config().pointer_type();
|
||||
@ -63,6 +71,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,
|
||||
unwind_context,
|
||||
sig,
|
||||
"__rust_alloc_error_handler",
|
||||
&alloc_error_handler_kind.fn_name(sym::oom),
|
||||
);
|
||||
|
||||
let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
|
||||
let mut data_ctx = DataContext::new();
|
||||
data_ctx.set_align(1);
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![feature(start, core_intrinsics, lang_items)]
|
||||
#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
@ -21,6 +21,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() -> ! {
|
||||
loop {}
|
||||
|
@ -5,10 +5,11 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::OomStrategy;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::GccContext;
|
||||
|
||||
pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind) {
|
||||
pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) {
|
||||
let context = &mods.context;
|
||||
let usize =
|
||||
match tcx.sess.target.pointer_width {
|
||||
@ -86,6 +87,37 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
|
||||
// as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
|
||||
}
|
||||
|
||||
let types = [usize, usize];
|
||||
let name = "__rust_alloc_error_handler".to_string();
|
||||
let args: Vec<_> = types.iter().enumerate()
|
||||
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
||||
.collect();
|
||||
let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
|
||||
|
||||
if tcx.sess.target.default_hidden_visibility {
|
||||
#[cfg(feature="master")]
|
||||
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||
}
|
||||
|
||||
let callee = alloc_error_handler_kind.fn_name(sym::oom);
|
||||
let args: Vec<_> = types.iter().enumerate()
|
||||
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
||||
.collect();
|
||||
let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false);
|
||||
#[cfg(feature="master")]
|
||||
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||
|
||||
let block = func.new_block("entry");
|
||||
|
||||
let args = args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
|
||||
.collect::<Vec<_>>();
|
||||
let _ret = context.new_call(None, callee, &args);
|
||||
//llvm::LLVMSetTailCall(ret, True);
|
||||
block.end_with_void_return(None);
|
||||
|
||||
let name = OomStrategy::SYMBOL.to_string();
|
||||
let global = context.new_global(None, GlobalKind::Exported, i8, name);
|
||||
let value = tcx.sess.opts.unstable_opts.oom.should_panic();
|
||||
|
@ -163,11 +163,11 @@ impl CodegenBackend for GccCodegenBackend {
|
||||
}
|
||||
|
||||
impl ExtraBackendMethods for GccCodegenBackend {
|
||||
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind) -> Self::Module {
|
||||
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
|
||||
let mut mods = GccContext {
|
||||
context: Context::default(),
|
||||
};
|
||||
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind); }
|
||||
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
|
||||
mods
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{DebugInfo, OomStrategy};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::debuginfo;
|
||||
use crate::llvm::{self, False, True};
|
||||
@ -14,6 +15,7 @@ pub(crate) unsafe fn codegen(
|
||||
module_llvm: &mut ModuleLlvm,
|
||||
module_name: &str,
|
||||
kind: AllocatorKind,
|
||||
alloc_error_handler_kind: AllocatorKind,
|
||||
) {
|
||||
let llcx = &*module_llvm.llcx;
|
||||
let llmod = module_llvm.llmod();
|
||||
@ -98,6 +100,52 @@ pub(crate) unsafe fn codegen(
|
||||
llvm::LLVMDisposeBuilder(llbuilder);
|
||||
}
|
||||
|
||||
// rust alloc error handler
|
||||
let args = [usize, usize]; // size, align
|
||||
|
||||
let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False);
|
||||
let name = "__rust_alloc_error_handler";
|
||||
let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
|
||||
// -> ! DIFlagNoReturn
|
||||
let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx);
|
||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]);
|
||||
|
||||
if tcx.sess.target.default_hidden_visibility {
|
||||
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
||||
}
|
||||
if tcx.sess.must_emit_unwind_tables() {
|
||||
let uwtable = attributes::uwtable_attr(llcx);
|
||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
|
||||
}
|
||||
|
||||
let callee = alloc_error_handler_kind.fn_name(sym::oom);
|
||||
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
||||
// -> ! DIFlagNoReturn
|
||||
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
|
||||
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
||||
|
||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
||||
|
||||
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
|
||||
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
|
||||
let args = args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
||||
.collect::<Vec<_>>();
|
||||
let ret = llvm::LLVMRustBuildCall(
|
||||
llbuilder,
|
||||
ty,
|
||||
callee,
|
||||
args.as_ptr(),
|
||||
args.len() as c_uint,
|
||||
[].as_ptr(),
|
||||
0 as c_uint,
|
||||
);
|
||||
llvm::LLVMSetTailCall(ret, True);
|
||||
llvm::LLVMBuildRetVoid(llbuilder);
|
||||
llvm::LLVMDisposeBuilder(llbuilder);
|
||||
|
||||
// __rust_alloc_error_handler_should_panic
|
||||
let name = OomStrategy::SYMBOL;
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||
|
@ -115,10 +115,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
module_name: &str,
|
||||
kind: AllocatorKind,
|
||||
alloc_error_handler_kind: AllocatorKind,
|
||||
) -> ModuleLlvm {
|
||||
let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
|
||||
unsafe {
|
||||
allocator::codegen(tcx, &mut module_llvm, module_name, kind);
|
||||
allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
|
||||
}
|
||||
module_llvm
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ fn exported_symbols_provider_local(
|
||||
for symbol_name in ALLOCATOR_METHODS
|
||||
.iter()
|
||||
.map(|method| format!("__rust_{}", method.name))
|
||||
.chain([OomStrategy::SYMBOL.to_string()])
|
||||
.chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
|
||||
{
|
||||
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
|
||||
|
||||
|
@ -635,9 +635,16 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||
if let Some(kind) = allocator_kind_for_codegen(tcx) {
|
||||
let llmod_id =
|
||||
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
|
||||
let module_llvm = tcx
|
||||
.sess
|
||||
.time("write_allocator_module", || backend.codegen_allocator(tcx, &llmod_id, kind));
|
||||
let module_llvm = tcx.sess.time("write_allocator_module", || {
|
||||
backend.codegen_allocator(
|
||||
tcx,
|
||||
&llmod_id,
|
||||
kind,
|
||||
// If allocator_kind is Some then alloc_error_handler_kind must
|
||||
// also be Some.
|
||||
tcx.alloc_error_handler_kind(()).unwrap(),
|
||||
)
|
||||
});
|
||||
|
||||
ongoing_codegen.submit_pre_codegened_module_to_llvm(
|
||||
tcx,
|
||||
|
@ -123,6 +123,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
|
||||
tcx: TyCtxt<'tcx>,
|
||||
module_name: &str,
|
||||
kind: AllocatorKind,
|
||||
alloc_error_handler_kind: AllocatorKind,
|
||||
) -> Self::Module;
|
||||
/// This generates the codegen unit and returns it along with
|
||||
/// a `u64` giving an estimate of the unit's processing cost.
|
||||
|
@ -291,6 +291,8 @@ declare_features! (
|
||||
(active, abi_x86_interrupt, "1.17.0", Some(40180), None),
|
||||
/// Allows additional const parameter types, such as `&'static str` or user defined types
|
||||
(incomplete, adt_const_params, "1.56.0", Some(95174), None),
|
||||
/// Allows defining an `#[alloc_error_handler]`.
|
||||
(active, alloc_error_handler, "1.29.0", Some(51540), None),
|
||||
/// Allows trait methods with arbitrary self types.
|
||||
(active, arbitrary_self_types, "1.23.0", Some(44874), None),
|
||||
/// Allows using `const` operands in inline assembly.
|
||||
|
@ -47,8 +47,6 @@ declare_features! (
|
||||
|
||||
(removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
|
||||
Some("merged into `#![feature(slice_patterns)]`")),
|
||||
/// Allows defining an `#[alloc_error_handler]`.
|
||||
(removed, alloc_error_handler, "CURRENT_RUSTC_VERSION", Some(51540), None, Some("now handled by panic handler")),
|
||||
(removed, allocator, "1.0.0", None, None, None),
|
||||
/// Allows a test to fail without failing the whole suite.
|
||||
(removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")),
|
||||
|
@ -777,7 +777,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(no_link, true);
|
||||
tracked!(no_profiler_runtime, true);
|
||||
tracked!(no_unique_section_names, true);
|
||||
tracked!(oom, OomStrategy::Unwind);
|
||||
tracked!(oom, OomStrategy::Panic);
|
||||
tracked!(osx_rpath_install_name, true);
|
||||
tracked!(packed_bundled_libs, true);
|
||||
tracked!(panic_abort_tests, true);
|
||||
|
@ -155,9 +155,19 @@ metadata_no_multiple_global_alloc =
|
||||
metadata_prev_global_alloc =
|
||||
previous global allocator defined here
|
||||
|
||||
metadata_no_multiple_alloc_error_handler =
|
||||
cannot define multiple allocation error handlers
|
||||
.label = cannot define a new allocation error handler
|
||||
|
||||
metadata_prev_alloc_error_handler =
|
||||
previous allocation error handler defined here
|
||||
|
||||
metadata_conflicting_global_alloc =
|
||||
the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
|
||||
|
||||
metadata_conflicting_alloc_error_handler =
|
||||
the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
|
||||
|
||||
metadata_global_alloc_required =
|
||||
no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
|
||||
|
||||
|
@ -38,8 +38,13 @@ pub struct CStore {
|
||||
/// This crate needs an allocator and either provides it itself, or finds it in a dependency.
|
||||
/// If the above is true, then this field denotes the kind of the found allocator.
|
||||
allocator_kind: Option<AllocatorKind>,
|
||||
/// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.
|
||||
/// If the above is true, then this field denotes the kind of the found allocator.
|
||||
alloc_error_handler_kind: Option<AllocatorKind>,
|
||||
/// This crate has a `#[global_allocator]` item.
|
||||
has_global_allocator: bool,
|
||||
/// This crate has a `#[alloc_error_handler]` item.
|
||||
has_alloc_error_handler: bool,
|
||||
|
||||
/// The interned [StableCrateId]s.
|
||||
pub(crate) stable_crate_ids: StableCrateIdMap,
|
||||
@ -216,10 +221,18 @@ impl CStore {
|
||||
self.allocator_kind
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
|
||||
self.alloc_error_handler_kind
|
||||
}
|
||||
|
||||
pub(crate) fn has_global_allocator(&self) -> bool {
|
||||
self.has_global_allocator
|
||||
}
|
||||
|
||||
pub(crate) fn has_alloc_error_handler(&self) -> bool {
|
||||
self.has_alloc_error_handler
|
||||
}
|
||||
|
||||
pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
|
||||
let json_unused_externs = tcx.sess.opts.json_unused_externs;
|
||||
|
||||
@ -255,7 +268,9 @@ impl CStore {
|
||||
metas: IndexVec::from_iter(iter::once(None)),
|
||||
injected_panic_runtime: None,
|
||||
allocator_kind: None,
|
||||
alloc_error_handler_kind: None,
|
||||
has_global_allocator: false,
|
||||
has_alloc_error_handler: false,
|
||||
stable_crate_ids,
|
||||
unused_externs: Vec::new(),
|
||||
}
|
||||
@ -761,6 +776,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||
}
|
||||
spans => !spans.is_empty(),
|
||||
};
|
||||
self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) {
|
||||
[span1, span2, ..] => {
|
||||
self.sess
|
||||
.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
|
||||
@ -801,6 +824,21 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut alloc_error_handler =
|
||||
self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate"));
|
||||
for (_, data) in self.cstore.iter_crate_data() {
|
||||
if data.has_alloc_error_handler() {
|
||||
match alloc_error_handler {
|
||||
Some(other_crate) => {
|
||||
self.sess.emit_err(errors::ConflictingAllocErrorHandler {
|
||||
crate_name: data.name(),
|
||||
other_crate_name: other_crate,
|
||||
});
|
||||
}
|
||||
None => alloc_error_handler = Some(data.name()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if global_allocator.is_some() {
|
||||
self.cstore.allocator_kind = Some(AllocatorKind::Global);
|
||||
@ -816,6 +854,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
||||
}
|
||||
self.cstore.allocator_kind = Some(AllocatorKind::Default);
|
||||
}
|
||||
|
||||
if alloc_error_handler.is_some() {
|
||||
self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
|
||||
} else {
|
||||
// The alloc crate provides a default allocation error handler if
|
||||
// one isn't specified.
|
||||
self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_dependency_if(
|
||||
@ -991,6 +1037,28 @@ fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
|
||||
f.spans
|
||||
}
|
||||
|
||||
fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
|
||||
struct Finder {
|
||||
name: Symbol,
|
||||
spans: Vec<Span>,
|
||||
}
|
||||
impl<'ast> visit::Visitor<'ast> for Finder {
|
||||
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||
if item.ident.name == self.name
|
||||
&& attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
|
||||
{
|
||||
self.spans.push(item.span);
|
||||
}
|
||||
visit::walk_item(self, item)
|
||||
}
|
||||
}
|
||||
|
||||
let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
|
||||
let mut f = Finder { name, spans: Vec::new() };
|
||||
visit::walk_crate(&mut f, krate);
|
||||
f.spans
|
||||
}
|
||||
|
||||
// On Windows the compiler would sometimes intermittently fail to open the
|
||||
// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
|
||||
// system still holds a lock on the file, so we retry a few times before calling it
|
||||
|
@ -352,6 +352,16 @@ pub struct NoMultipleGlobalAlloc {
|
||||
pub span1: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(metadata_no_multiple_alloc_error_handler)]
|
||||
pub struct NoMultipleAllocErrorHandler {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span2: Span,
|
||||
#[label(metadata_prev_alloc_error_handler)]
|
||||
pub span1: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(metadata_conflicting_global_alloc)]
|
||||
pub struct ConflictingGlobalAlloc {
|
||||
@ -359,6 +369,13 @@ pub struct ConflictingGlobalAlloc {
|
||||
pub other_crate_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(metadata_conflicting_alloc_error_handler)]
|
||||
pub struct ConflictingAllocErrorHandler {
|
||||
pub crate_name: Symbol,
|
||||
pub other_crate_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(metadata_global_alloc_required)]
|
||||
pub struct GlobalAllocRequired;
|
||||
|
@ -1683,6 +1683,10 @@ impl CrateMetadata {
|
||||
self.root.has_global_allocator
|
||||
}
|
||||
|
||||
pub(crate) fn has_alloc_error_handler(&self) -> bool {
|
||||
self.root.has_alloc_error_handler
|
||||
}
|
||||
|
||||
pub(crate) fn has_default_lib_allocator(&self) -> bool {
|
||||
self.root.has_default_lib_allocator
|
||||
}
|
||||
|
@ -290,6 +290,7 @@ provide! { tcx, def_id, other, cdata,
|
||||
is_panic_runtime => { cdata.root.panic_runtime }
|
||||
is_compiler_builtins => { cdata.root.compiler_builtins }
|
||||
has_global_allocator => { cdata.root.has_global_allocator }
|
||||
has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
|
||||
has_panic_handler => { cdata.root.has_panic_handler }
|
||||
is_profiler_runtime => { cdata.root.profiler_runtime }
|
||||
required_panic_strategy => { cdata.root.required_panic_strategy }
|
||||
@ -378,6 +379,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
||||
// resolve! Does this work? Unsure! That's what the issue is about
|
||||
*providers = Providers {
|
||||
allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
|
||||
alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
|
||||
is_private_dep: |_tcx, LocalCrate| false,
|
||||
native_library: |tcx, id| {
|
||||
tcx.native_libraries(id.krate)
|
||||
@ -494,6 +496,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
||||
|
||||
dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
|
||||
has_global_allocator: |tcx, LocalCrate| CStore::from_tcx(tcx).has_global_allocator(),
|
||||
has_alloc_error_handler: |tcx, LocalCrate| CStore::from_tcx(tcx).has_alloc_error_handler(),
|
||||
postorder_cnums: |tcx, ()| {
|
||||
tcx.arena
|
||||
.alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
|
||||
|
@ -676,6 +676,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
|
||||
edition: tcx.sess.edition(),
|
||||
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
|
||||
has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
|
||||
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
|
||||
has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator),
|
||||
proc_macro_data,
|
||||
|
@ -225,6 +225,7 @@ pub(crate) struct CrateRoot {
|
||||
panic_in_drop_strategy: PanicStrategy,
|
||||
edition: Edition,
|
||||
has_global_allocator: bool,
|
||||
has_alloc_error_handler: bool,
|
||||
has_panic_handler: bool,
|
||||
has_default_lib_allocator: bool,
|
||||
|
||||
|
@ -1351,6 +1351,13 @@ rustc_queries! {
|
||||
desc { "checking if the crate has_global_allocator" }
|
||||
separate_provide_extern
|
||||
}
|
||||
query has_alloc_error_handler(_: CrateNum) -> bool {
|
||||
// This query depends on untracked global state in CStore
|
||||
eval_always
|
||||
fatal_cycle
|
||||
desc { "checking if the crate has_alloc_error_handler" }
|
||||
separate_provide_extern
|
||||
}
|
||||
query has_panic_handler(_: CrateNum) -> bool {
|
||||
fatal_cycle
|
||||
desc { "checking if the crate has_panic_handler" }
|
||||
@ -1723,6 +1730,10 @@ rustc_queries! {
|
||||
eval_always
|
||||
desc { "getting the allocator kind for the current crate" }
|
||||
}
|
||||
query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> {
|
||||
eval_always
|
||||
desc { "alloc error handler kind for the current crate" }
|
||||
}
|
||||
|
||||
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
|
||||
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
|
||||
|
@ -3048,9 +3048,9 @@ pub(crate) mod dep_tracking {
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum OomStrategy {
|
||||
/// Generate a panic that can be caught by `catch_unwind`.
|
||||
Unwind,
|
||||
Panic,
|
||||
|
||||
/// Calls the panic hook as normal but aborts instead of unwinding.
|
||||
/// Abort the process immediately.
|
||||
Abort,
|
||||
}
|
||||
|
||||
@ -3059,7 +3059,7 @@ impl OomStrategy {
|
||||
|
||||
pub fn should_panic(self) -> u8 {
|
||||
match self {
|
||||
OomStrategy::Unwind => 1,
|
||||
OomStrategy::Panic => 1,
|
||||
OomStrategy::Abort => 0,
|
||||
}
|
||||
}
|
||||
|
@ -662,7 +662,7 @@ mod parse {
|
||||
|
||||
pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some("unwind") => *slot = OomStrategy::Unwind,
|
||||
Some("panic") => *slot = OomStrategy::Panic,
|
||||
Some("abort") => *slot = OomStrategy::Abort,
|
||||
_ => return false,
|
||||
}
|
||||
|
@ -35,6 +35,3 @@ compiler-builtins-mem = ['compiler_builtins/mem']
|
||||
compiler-builtins-c = ["compiler_builtins/c"]
|
||||
compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
|
||||
compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
|
||||
|
||||
# Make panics and failed asserts immediately abort without formatting any message
|
||||
panic_immediate_abort = ["core/panic_immediate_abort"]
|
||||
|
@ -14,11 +14,6 @@ use core::ptr::{self, NonNull};
|
||||
#[doc(inline)]
|
||||
pub use core::alloc::*;
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::any::Any;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::panic::BoxMeUp;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@ -348,77 +343,14 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
|
||||
}
|
||||
}
|
||||
|
||||
/// Payload passed to the panic handler when `handle_alloc_error` is called.
|
||||
#[unstable(feature = "panic_oom_payload", issue = "none")]
|
||||
#[derive(Debug)]
|
||||
pub struct AllocErrorPanicPayload {
|
||||
layout: Layout,
|
||||
}
|
||||
|
||||
impl AllocErrorPanicPayload {
|
||||
/// Internal function for the standard library to clone a payload.
|
||||
#[unstable(feature = "std_internals", issue = "none")]
|
||||
#[doc(hidden)]
|
||||
pub fn internal_clone(&self) -> Self {
|
||||
AllocErrorPanicPayload { layout: self.layout }
|
||||
}
|
||||
|
||||
/// Returns the [`Layout`] of the allocation attempt that caused the error.
|
||||
#[unstable(feature = "panic_oom_payload", issue = "none")]
|
||||
pub fn layout(&self) -> Layout {
|
||||
self.layout
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "std_internals", issue = "none")]
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
unsafe impl BoxMeUp for AllocErrorPanicPayload {
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||
use crate::boxed::Box;
|
||||
Box::into_raw(Box::new(self.internal_clone()))
|
||||
}
|
||||
|
||||
fn get(&mut self) -> &(dyn Any + Send) {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// # Allocation error handler
|
||||
|
||||
#[cfg(all(not(no_global_oom_handling), not(test)))]
|
||||
fn rust_oom(layout: Layout) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
core::intrinsics::abort()
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
// that gets resolved to the `#[panic_handler]` function.
|
||||
#[lang = "panic_impl"]
|
||||
fn panic_impl(pi: &core::panic::PanicInfo<'_>) -> !;
|
||||
|
||||
// This symbol is emitted by rustc .
|
||||
// Its value depends on the -Zoom={unwind,abort} compiler option.
|
||||
static __rust_alloc_error_handler_should_panic: u8;
|
||||
}
|
||||
|
||||
// Hack to work around issues with the lifetime of Arguments.
|
||||
match format_args!("memory allocation of {} bytes failed", layout.size()) {
|
||||
fmt => {
|
||||
// Create a PanicInfo with a custom payload for the panic handler.
|
||||
let can_unwind = unsafe { __rust_alloc_error_handler_should_panic != 0 };
|
||||
let mut pi = core::panic::PanicInfo::internal_constructor(
|
||||
Some(&fmt),
|
||||
core::panic::Location::caller(),
|
||||
can_unwind,
|
||||
);
|
||||
let payload = AllocErrorPanicPayload { layout };
|
||||
pi.set_payload(&payload);
|
||||
|
||||
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
|
||||
unsafe { panic_impl(&pi) }
|
||||
}
|
||||
}
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
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.
|
||||
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
|
||||
}
|
||||
|
||||
/// Abort on memory allocation error or failure.
|
||||
@ -426,6 +358,13 @@ fn rust_oom(layout: Layout) -> ! {
|
||||
/// Callers of memory allocation APIs wishing to abort computation
|
||||
/// in response to an allocation error are encouraged to call this function,
|
||||
/// rather than directly invoking `panic!` or similar.
|
||||
///
|
||||
/// The default behavior of this function is to print a message to standard error
|
||||
/// and abort the process.
|
||||
/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
|
||||
///
|
||||
/// [`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")]
|
||||
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
|
||||
#[cfg(all(not(no_global_oom_handling), not(test)))]
|
||||
@ -436,7 +375,9 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
|
||||
}
|
||||
|
||||
fn rt_error(layout: Layout) -> ! {
|
||||
rust_oom(layout);
|
||||
unsafe {
|
||||
__rust_alloc_error_handler(layout.size(), layout.align());
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
|
||||
@ -446,7 +387,6 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
|
||||
#[cfg(all(not(no_global_oom_handling), test))]
|
||||
pub use std::alloc::handle_alloc_error;
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
#[cfg(all(not(no_global_oom_handling), not(test)))]
|
||||
#[doc(hidden)]
|
||||
#[allow(unused_attributes)]
|
||||
@ -458,7 +398,7 @@ pub mod __alloc_error_handler {
|
||||
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
|
||||
extern "Rust" {
|
||||
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
|
||||
// Its value depends on the -Zoom={unwind,abort} compiler option.
|
||||
// Its value depends on the -Zoom={panic,abort} compiler option.
|
||||
static __rust_alloc_error_handler_should_panic: u8;
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,6 @@
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_uninit_array_transpose)]
|
||||
#![feature(panic_internals)]
|
||||
#![feature(pattern)]
|
||||
#![feature(pointer_byte_offsets)]
|
||||
#![feature(provide_any)]
|
||||
|
@ -1531,6 +1531,16 @@ pub(crate) mod builtin {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
/// Attribute macro applied to a function to register it as a handler for allocation failure.
|
||||
///
|
||||
/// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).
|
||||
#[unstable(feature = "alloc_error_handler", issue = "51540")]
|
||||
#[allow_internal_unstable(rustc_attrs)]
|
||||
#[rustc_builtin_macro]
|
||||
pub macro alloc_error_handler($item:item) {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
/// Keeps the item it's applied to if the passed path is accessible, and removes it otherwise.
|
||||
#[unstable(
|
||||
feature = "cfg_accessible",
|
||||
|
@ -76,7 +76,9 @@ pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
|
||||
// Do not `doc(no_inline)` so that they become doc items on their own
|
||||
// (no public module for them to be re-exported from).
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
|
||||
pub use crate::macros::builtin::{
|
||||
alloc_error_handler, bench, derive, global_allocator, test, test_case,
|
||||
};
|
||||
|
||||
#[unstable(feature = "derive_const", issue = "none")]
|
||||
pub use crate::macros::builtin::derive_const;
|
||||
|
@ -67,7 +67,7 @@ llvm-libunwind = ["unwind/llvm-libunwind"]
|
||||
system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
|
||||
|
||||
# Make panics and failed asserts immediately abort without formatting any message
|
||||
panic_immediate_abort = ["alloc/panic_immediate_abort"]
|
||||
panic_immediate_abort = ["core/panic_immediate_abort"]
|
||||
|
||||
# Enable std_detect default features for stdarch/crates/std_detect:
|
||||
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
|
||||
|
@ -57,8 +57,9 @@
|
||||
#![stable(feature = "alloc_module", since = "1.28.0")]
|
||||
|
||||
use core::intrinsics;
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
use core::{mem, ptr};
|
||||
|
||||
#[stable(feature = "alloc_module", since = "1.28.0")]
|
||||
#[doc(inline)]
|
||||
@ -285,6 +286,76 @@ unsafe impl Allocator for System {
|
||||
}
|
||||
}
|
||||
|
||||
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
/// Registers a custom allocation error hook, replacing any that was previously registered.
|
||||
///
|
||||
/// The allocation error hook is invoked when an infallible memory allocation fails, before
|
||||
/// the runtime aborts. The default hook prints a message to standard error,
|
||||
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
|
||||
/// [`take_alloc_error_hook`] functions.
|
||||
///
|
||||
/// The hook is provided with a `Layout` struct which contains information
|
||||
/// about the allocation that failed.
|
||||
///
|
||||
/// The allocation error hook is a global resource.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(alloc_error_hook)]
|
||||
///
|
||||
/// use std::alloc::{Layout, set_alloc_error_hook};
|
||||
///
|
||||
/// fn custom_alloc_error_hook(layout: Layout) {
|
||||
/// panic!("memory allocation of {} bytes failed", layout.size());
|
||||
/// }
|
||||
///
|
||||
/// set_alloc_error_hook(custom_alloc_error_hook);
|
||||
/// ```
|
||||
#[unstable(feature = "alloc_error_hook", issue = "51245")]
|
||||
pub fn set_alloc_error_hook(hook: fn(Layout)) {
|
||||
HOOK.store(hook as *mut (), Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// Unregisters the current allocation error hook, returning it.
|
||||
///
|
||||
/// *See also the function [`set_alloc_error_hook`].*
|
||||
///
|
||||
/// If no custom hook is registered, the default hook will be returned.
|
||||
#[unstable(feature = "alloc_error_hook", issue = "51245")]
|
||||
pub fn take_alloc_error_hook() -> fn(Layout) {
|
||||
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
|
||||
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
|
||||
}
|
||||
|
||||
fn default_alloc_error_hook(layout: Layout) {
|
||||
extern "Rust" {
|
||||
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
|
||||
// Its value depends on the -Zoom={panic,abort} compiler option.
|
||||
static __rust_alloc_error_handler_should_panic: u8;
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
|
||||
panic!("memory allocation of {} bytes failed", layout.size());
|
||||
} else {
|
||||
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[doc(hidden)]
|
||||
#[alloc_error_handler]
|
||||
#[unstable(feature = "alloc_internals", issue = "none")]
|
||||
pub fn rust_oom(layout: Layout) -> ! {
|
||||
let hook = HOOK.load(Ordering::SeqCst);
|
||||
let hook: fn(Layout) =
|
||||
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
|
||||
hook(layout);
|
||||
crate::process::abort()
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[doc(hidden)]
|
||||
#[allow(unused_attributes)]
|
||||
|
@ -236,6 +236,7 @@
|
||||
//
|
||||
// Language features:
|
||||
// tidy-alphabetical-start
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(allocator_internals)]
|
||||
#![feature(allow_internal_unsafe)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
@ -319,7 +320,6 @@
|
||||
#![feature(get_mut_unchecked)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(panic_oom_payload)]
|
||||
#![feature(slice_concat_trait)]
|
||||
#![feature(thin_box)]
|
||||
#![feature(try_reserve_kind)]
|
||||
|
@ -245,24 +245,19 @@ fn default_hook(info: &PanicInfo<'_>) {
|
||||
|
||||
// The current implementation always returns `Some`.
|
||||
let location = info.location().unwrap();
|
||||
|
||||
let msg = match info.payload().downcast_ref::<&'static str>() {
|
||||
Some(s) => *s,
|
||||
None => match info.payload().downcast_ref::<String>() {
|
||||
Some(s) => &s[..],
|
||||
None => "Box<dyn Any>",
|
||||
},
|
||||
};
|
||||
let thread = thread_info::current_thread();
|
||||
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
|
||||
|
||||
let write = |err: &mut dyn crate::io::Write| {
|
||||
// Use the panic message directly if available, otherwise take it from
|
||||
// the payload.
|
||||
if let Some(msg) = info.message() {
|
||||
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
|
||||
} else {
|
||||
let msg = if let Some(s) = info.payload().downcast_ref::<&'static str>() {
|
||||
*s
|
||||
} else if let Some(s) = info.payload().downcast_ref::<String>() {
|
||||
&s[..]
|
||||
} else {
|
||||
"Box<dyn Any>"
|
||||
};
|
||||
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
|
||||
}
|
||||
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
|
||||
|
||||
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
@ -529,8 +524,6 @@ pub fn panicking() -> bool {
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
|
||||
use alloc::alloc::AllocErrorPanicPayload;
|
||||
|
||||
struct PanicPayload<'a> {
|
||||
inner: &'a fmt::Arguments<'a>,
|
||||
string: Option<String>,
|
||||
@ -557,7 +550,8 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
|
||||
unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||
// We do two allocations here, unfortunately. But (a) they're required with the current
|
||||
// scheme, and (b) OOM uses its own separate payload type which doesn't allocate.
|
||||
// scheme, and (b) we don't handle panic + OOM properly anyway (see comment in
|
||||
// begin_panic below).
|
||||
let contents = mem::take(self.fill());
|
||||
Box::into_raw(Box::new(contents))
|
||||
}
|
||||
@ -582,14 +576,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
|
||||
let loc = info.location().unwrap(); // The current implementation always returns Some
|
||||
let msg = info.message().unwrap(); // The current implementation always returns Some
|
||||
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
|
||||
if let Some(payload) = info.payload().downcast_ref::<AllocErrorPanicPayload>() {
|
||||
rust_panic_with_hook(
|
||||
&mut payload.internal_clone(),
|
||||
info.message(),
|
||||
loc,
|
||||
info.can_unwind(),
|
||||
);
|
||||
} else if let Some(msg) = msg.as_str() {
|
||||
if let Some(msg) = msg.as_str() {
|
||||
rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
|
||||
} else {
|
||||
rust_panic_with_hook(
|
||||
@ -636,7 +623,11 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
|
||||
|
||||
unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
|
||||
fn take_box(&mut self) -> *mut (dyn Any + Send) {
|
||||
// Note that this should be the only allocation performed in this code path.
|
||||
// Note that this should be the only allocation performed in this code path. Currently
|
||||
// this means that panic!() on OOM will invoke this code path, but then again we're not
|
||||
// really ready for panic on OOM anyway. If we do start doing this, then we should
|
||||
// propagate this allocation to be performed in the parent of this thread instead of the
|
||||
// thread that's panicking.
|
||||
let data = match self.inner.take() {
|
||||
Some(a) => Box::new(a) as Box<dyn Any + Send>,
|
||||
None => process::abort(),
|
||||
|
@ -60,7 +60,9 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
|
||||
// Do not `doc(no_inline)` so that they become doc items on their own
|
||||
// (no public module for them to be re-exported from).
|
||||
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||
pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
|
||||
pub use core::prelude::v1::{
|
||||
alloc_error_handler, bench, derive, global_allocator, test, test_case,
|
||||
};
|
||||
|
||||
#[unstable(feature = "derive_const", issue = "none")]
|
||||
pub use core::prelude::v1::derive_const;
|
||||
|
@ -381,6 +381,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
|
||||
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
|
||||
rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
|
||||
gated!(
|
||||
alloc_error_handler, Normal, template!(Word), WarnFollowing,
|
||||
experimental!(alloc_error_handler)
|
||||
),
|
||||
gated!(
|
||||
default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
|
||||
experimental!(default_lib_allocator),
|
||||
|
@ -136,10 +136,10 @@
|
||||
134| |
|
||||
135| |impl std::fmt::Debug for Foo {
|
||||
136| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
137| 9| write!(f, "try and succeed")?;
|
||||
137| 7| write!(f, "try and succeed")?;
|
||||
^0
|
||||
138| 9| Ok(())
|
||||
139| 9| }
|
||||
138| 7| Ok(())
|
||||
139| 7| }
|
||||
140| |}
|
||||
141| |
|
||||
142| |static mut DEBUG_LEVEL_ENABLED: bool = false;
|
||||
|
@ -6,3 +6,4 @@ all:
|
||||
$(RUSTC) --emit=obj app.rs
|
||||
nm $(TMPDIR)/app.o | $(CGREP) rust_begin_unwind
|
||||
nm $(TMPDIR)/app.o | $(CGREP) rust_eh_personality
|
||||
nm $(TMPDIR)/app.o | $(CGREP) __rg_oom
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![crate_type = "bin"]
|
||||
#![feature(lang_items)]
|
||||
#![feature(lang_items, alloc_error_handler)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
@ -13,3 +13,8 @@ fn panic(_: &PanicInfo) -> ! {
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh() {}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn oom(_: Layout) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
19
tests/run-make/issue-69368/Makefile
Normal file
19
tests/run-make/issue-69368/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
# ignore-cross-compile
|
||||
include ../tools.mk
|
||||
|
||||
# Test that previously triggered a linker failure with root cause
|
||||
# similar to one found in the issue #69368.
|
||||
#
|
||||
# The crate that provides oom lang item is missing some other lang
|
||||
# items. Necessary to prevent the use of start-group / end-group.
|
||||
#
|
||||
# The weak lang items are defined in a separate compilation units,
|
||||
# so that linker could omit them if not used.
|
||||
#
|
||||
# The crates that need those weak lang items are dependencies of
|
||||
# crates that provide them.
|
||||
|
||||
all:
|
||||
$(RUSTC) a.rs
|
||||
$(RUSTC) b.rs
|
||||
$(RUSTC) c.rs
|
26
tests/run-make/issue-69368/a.rs
Normal file
26
tests/run-make/issue-69368/a.rs
Normal file
@ -0,0 +1,26 @@
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(lang_items)]
|
||||
#![feature(panic_unwind)]
|
||||
#![no_std]
|
||||
|
||||
extern crate panic_unwind;
|
||||
|
||||
#[panic_handler]
|
||||
pub fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn __rust_drop_panic() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn __rust_foreign_exception() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() {
|
||||
loop {}
|
||||
}
|
8
tests/run-make/issue-69368/b.rs
Normal file
8
tests/run-make/issue-69368/b.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![no_std]
|
||||
|
||||
#[alloc_error_handler]
|
||||
pub fn error_handler(_: core::alloc::Layout) -> ! {
|
||||
panic!();
|
||||
}
|
34
tests/run-make/issue-69368/c.rs
Normal file
34
tests/run-make/issue-69368/c.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#![crate_type = "bin"]
|
||||
#![feature(start)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate a;
|
||||
extern crate b;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::alloc::*;
|
||||
|
||||
struct Allocator;
|
||||
|
||||
unsafe impl GlobalAlloc for Allocator {
|
||||
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Allocator = Allocator;
|
||||
|
||||
#[start]
|
||||
fn main(argc: isize, _argv: *const *const u8) -> isize {
|
||||
let mut v = Vec::new();
|
||||
for i in 0..argc {
|
||||
v.push(i);
|
||||
}
|
||||
v.iter().sum()
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#![feature(panic_handler)]
|
||||
#![feature(panic_handler, alloc_error_handler)]
|
||||
#![crate_type = "cdylib"]
|
||||
#![no_std]
|
||||
|
||||
@ -24,6 +24,11 @@ pub extern fn foo(a: u32) -> u32 {
|
||||
a * 2
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn a(_: core::alloc::Layout) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn b(_: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
|
18
tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs
Normal file
18
tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// compile-flags:-C panic=abort
|
||||
|
||||
#![feature(alloc_error_handler)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::alloc::Layout;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn oom(
|
||||
info: &Layout, //~^ ERROR mismatched types
|
||||
) -> () //~^^ ERROR mismatched types
|
||||
{
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
|
@ -0,0 +1,44 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/alloc-error-handler-bad-signature-1.rs:10:1
|
||||
|
|
||||
LL | #[alloc_error_handler]
|
||||
| ---------------------- in this procedural macro expansion
|
||||
LL | // fn oom(
|
||||
LL | || info: &Layout,
|
||||
LL | || ) -> ()
|
||||
| ||_______- arguments to this function are incorrect
|
||||
LL | | {
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| |__^ expected `&Layout`, found `Layout`
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/alloc-error-handler-bad-signature-1.rs:10:4
|
||||
|
|
||||
LL | fn oom(
|
||||
| ^^^
|
||||
LL | info: &Layout,
|
||||
| -------------
|
||||
= note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/alloc-error-handler-bad-signature-1.rs:10:1
|
||||
|
|
||||
LL | #[alloc_error_handler]
|
||||
| ---------------------- in this procedural macro expansion
|
||||
LL | // fn oom(
|
||||
LL | || info: &Layout,
|
||||
LL | || ) -> ()
|
||||
| ||_______^ expected `!`, found `()`
|
||||
LL | | {
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| |__- expected `!` because of return type
|
||||
|
|
||||
= note: expected type `!`
|
||||
found unit type `()`
|
||||
= note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
17
tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs
Normal file
17
tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// compile-flags:-C panic=abort
|
||||
|
||||
#![feature(alloc_error_handler)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
struct Layout;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn oom(
|
||||
info: Layout, //~^ ERROR mismatched types
|
||||
) { //~^^ ERROR mismatched types
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
|
@ -0,0 +1,50 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/alloc-error-handler-bad-signature-2.rs:10:1
|
||||
|
|
||||
LL | #[alloc_error_handler]
|
||||
| ---------------------- in this procedural macro expansion
|
||||
LL | // fn oom(
|
||||
LL | || info: Layout,
|
||||
LL | || ) {
|
||||
| ||_- arguments to this function are incorrect
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| |__^ expected `Layout`, found `core::alloc::Layout`
|
||||
|
|
||||
= note: `core::alloc::Layout` and `Layout` have similar names, but are actually distinct types
|
||||
note: `core::alloc::Layout` is defined in crate `core`
|
||||
--> $SRC_DIR/core/src/alloc/layout.rs:LL:COL
|
||||
note: `Layout` is defined in the current crate
|
||||
--> $DIR/alloc-error-handler-bad-signature-2.rs:7:1
|
||||
|
|
||||
LL | struct Layout;
|
||||
| ^^^^^^^^^^^^^
|
||||
note: function defined here
|
||||
--> $DIR/alloc-error-handler-bad-signature-2.rs:10:4
|
||||
|
|
||||
LL | fn oom(
|
||||
| ^^^
|
||||
LL | info: Layout,
|
||||
| ------------
|
||||
= note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/alloc-error-handler-bad-signature-2.rs:10:1
|
||||
|
|
||||
LL | #[alloc_error_handler]
|
||||
| ---------------------- in this procedural macro expansion
|
||||
LL | // fn oom(
|
||||
LL | || info: Layout,
|
||||
LL | || ) {
|
||||
| ||_^ expected `!`, found `()`
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| |__- expected `!` because of return type
|
||||
|
|
||||
= note: expected type `!`
|
||||
found unit type `()`
|
||||
= note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
15
tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs
Normal file
15
tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// compile-flags:-C panic=abort
|
||||
|
||||
#![feature(alloc_error_handler)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
struct Layout;
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn oom() -> ! { //~ ERROR function takes 0 arguments but 1 argument was supplied
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
|
@ -0,0 +1,21 @@
|
||||
error[E0061]: this function takes 0 arguments but 1 argument was supplied
|
||||
--> $DIR/alloc-error-handler-bad-signature-3.rs:10:1
|
||||
|
|
||||
LL | #[alloc_error_handler]
|
||||
| ---------------------- in this procedural macro expansion
|
||||
LL | fn oom() -> ! {
|
||||
| _-^^^^^^^^^^^^
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| |_- unexpected argument of type `core::alloc::Layout`
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/alloc-error-handler-bad-signature-3.rs:10:4
|
||||
|
|
||||
LL | fn oom() -> ! {
|
||||
| ^^^
|
||||
= note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0061`.
|
@ -2,7 +2,7 @@
|
||||
// ignore-emscripten no processes
|
||||
// ignore-sgx no processes
|
||||
|
||||
use std::alloc::{handle_alloc_error, Layout};
|
||||
use std::alloc::{Layout, handle_alloc_error};
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
@ -24,5 +24,5 @@ fn main() {
|
||||
.strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n")
|
||||
.unwrap_or(stderr);
|
||||
|
||||
assert!(stderr.contains("memory allocation of 42 bytes failed"));
|
||||
assert_eq!(stderr, "memory allocation of 42 bytes failed\n");
|
||||
}
|
||||
|
84
tests/ui/allocator/no_std-alloc-error-handler-custom.rs
Normal file
84
tests/ui/allocator/no_std-alloc-error-handler-custom.rs
Normal file
@ -0,0 +1,84 @@
|
||||
// run-pass
|
||||
// ignore-android 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(rustc_private, lang_items)]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
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 alloc::string::ToString;
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::ptr::null_mut;
|
||||
|
||||
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();
|
||||
libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, 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 {
|
||||
let s = panic_info.to_string();
|
||||
const PSTR: &str = "panic occurred: ";
|
||||
const CR: &str = "\n";
|
||||
libc::write(libc::STDERR_FILENO, PSTR.as_ptr() as *const _, PSTR.len());
|
||||
libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len());
|
||||
libc::write(libc::STDERR_FILENO, CR.as_ptr() as *const _, CR.len());
|
||||
libc::exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
|
||||
// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
|
||||
// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
|
||||
// unwind. So, for this test case we will define the symbol.
|
||||
#[lang = "eh_personality"]
|
||||
extern "C" fn rust_eh_personality() {}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
|
||||
|
||||
#[no_mangle]
|
||||
fn main(_argc: i32, _argv: *const *const u8) -> isize {
|
||||
let zero = Box::<Page>::new(Default::default());
|
||||
helper::work_with(&zero);
|
||||
1
|
||||
}
|
16
tests/ui/feature-gates/feature-gate-alloc-error-handler.rs
Normal file
16
tests/ui/feature-gates/feature-gate-alloc-error-handler.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// compile-flags:-C panic=abort
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::alloc::Layout;
|
||||
|
||||
#[alloc_error_handler] //~ ERROR use of unstable library feature 'alloc_error_handler'
|
||||
fn oom(info: Layout) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0658]: use of unstable library feature 'alloc_error_handler'
|
||||
--> $DIR/feature-gate-alloc-error-handler.rs:8:3
|
||||
|
|
||||
LL | #[alloc_error_handler]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #51540 <https://github.com/rust-lang/rust/issues/51540> for more information
|
||||
= help: add `#![feature(alloc_error_handler)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -3,10 +3,16 @@
|
||||
|
||||
#![no_std]
|
||||
#![crate_type = "staticlib"]
|
||||
#![feature(alloc_error_handler)]
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn oom(_: core::alloc::Layout) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
extern crate alloc;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// compile-flags: -Z oom=unwind
|
||||
// compile-flags: -Z oom=panic
|
||||
// run-pass
|
||||
// no-prefer-dynamic
|
||||
// needs-unwind
|
||||
|
Loading…
x
Reference in New Issue
Block a user