mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #88098 - Amanieu:oom_panic, r=nagisa
Implement -Z oom=panic This PR removes the `#[rustc_allocator_nounwind]` attribute on `alloc_error_handler` which allows it to unwind with a panic instead of always aborting. This is then used to implement `-Z oom=panic` as per RFC 2116 (tracking issue #43596). Perf and binary size tests show negligible impact.
This commit is contained in:
commit
d6f3a4ecb4
@ -4,6 +4,7 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
|
||||
use rustc_session::config::OomStrategy;
|
||||
|
||||
/// Returns whether an allocator shim was created
|
||||
pub(crate) fn codegen(
|
||||
@ -18,7 +19,13 @@ pub(crate) fn codegen(
|
||||
if any_dynamic_crate {
|
||||
false
|
||||
} else if let Some(kind) = tcx.allocator_kind(()) {
|
||||
codegen_inner(module, unwind_context, kind, tcx.lang_items().oom().is_some());
|
||||
codegen_inner(
|
||||
module,
|
||||
unwind_context,
|
||||
kind,
|
||||
tcx.lang_items().oom().is_some(),
|
||||
tcx.sess.opts.debugging_opts.oom,
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -30,6 +37,7 @@ fn codegen_inner(
|
||||
unwind_context: &mut UnwindContext,
|
||||
kind: AllocatorKind,
|
||||
has_alloc_error_handler: bool,
|
||||
oom_strategy: OomStrategy,
|
||||
) {
|
||||
let usize_ty = module.target_config().pointer_type();
|
||||
|
||||
@ -129,4 +137,11 @@ fn codegen_inner(
|
||||
}
|
||||
module.define_function(func_id, &mut ctx).unwrap();
|
||||
unwind_context.add_function(func_id, &ctx, module.isa());
|
||||
|
||||
let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
|
||||
let mut data_ctx = DataContext::new();
|
||||
data_ctx.set_align(1);
|
||||
let val = oom_strategy.should_panic();
|
||||
data_ctx.define(Box::new([val]));
|
||||
module.define_data(data_id, &data_ctx).unwrap();
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use gccjit::{FunctionType, ToRValue};
|
||||
use gccjit::{FunctionType, GlobalKind, ToRValue};
|
||||
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;
|
||||
@ -113,4 +114,10 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
|
||||
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.debugging_opts.oom.should_panic();
|
||||
let value = context.new_rvalue_from_int(i8, value as i32);
|
||||
global.global_set_initializer_rvalue(value);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use libc::c_uint;
|
||||
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_session::config::{DebugInfo, OomStrategy};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::debuginfo;
|
||||
@ -139,6 +139,16 @@ pub(crate) unsafe fn codegen(
|
||||
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);
|
||||
if tcx.sess.target.default_hidden_visibility {
|
||||
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
|
||||
}
|
||||
let val = tcx.sess.opts.debugging_opts.oom.should_panic();
|
||||
let llval = llvm::LLVMConstInt(i8, val as u64, False);
|
||||
llvm::LLVMSetInitializer(ll_g, llval);
|
||||
|
||||
if tcx.sess.opts.debuginfo != DebugInfo::None {
|
||||
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
|
||||
debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
|
||||
|
@ -9,8 +9,8 @@ use rustc_session::config::{
|
||||
rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
|
||||
};
|
||||
use rustc_session::config::{
|
||||
BranchProtection, Externs, OutputType, OutputTypes, PAuthKey, PacRet, SymbolManglingVersion,
|
||||
WasiExecModel,
|
||||
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
|
||||
SymbolManglingVersion, WasiExecModel,
|
||||
};
|
||||
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
|
||||
use rustc_session::lint::Level;
|
||||
@ -758,6 +758,7 @@ fn test_debugging_options_tracking_hash() {
|
||||
tracked!(no_link, true);
|
||||
tracked!(no_unique_section_names, true);
|
||||
tracked!(no_profiler_runtime, true);
|
||||
tracked!(oom, OomStrategy::Panic);
|
||||
tracked!(osx_rpath_install_name, true);
|
||||
tracked!(panic_abort_tests, true);
|
||||
tracked!(panic_in_drop, PanicStrategy::Abort);
|
||||
|
@ -2842,9 +2842,9 @@ impl PpMode {
|
||||
crate mod dep_tracking {
|
||||
use super::{
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
||||
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType,
|
||||
OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion,
|
||||
TrimmedDefPaths,
|
||||
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
|
||||
OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
|
||||
SymbolManglingVersion, TrimmedDefPaths,
|
||||
};
|
||||
use crate::lint;
|
||||
use crate::options::WasiExecModel;
|
||||
@ -2940,6 +2940,7 @@ crate mod dep_tracking {
|
||||
RealFileName,
|
||||
LocationDetail,
|
||||
BranchProtection,
|
||||
OomStrategy,
|
||||
);
|
||||
|
||||
impl<T1, T2> DepTrackingHash for (T1, T2)
|
||||
@ -3029,3 +3030,24 @@ crate mod dep_tracking {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Default behavior to use in out-of-memory situations.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum OomStrategy {
|
||||
/// Generate a panic that can be caught by `catch_unwind`.
|
||||
Panic,
|
||||
|
||||
/// Abort the process immediately.
|
||||
Abort,
|
||||
}
|
||||
|
||||
impl OomStrategy {
|
||||
pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
|
||||
|
||||
pub fn should_panic(self) -> u8 {
|
||||
match self {
|
||||
OomStrategy::Panic => 1,
|
||||
OomStrategy::Abort => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,6 +375,7 @@ mod desc {
|
||||
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
||||
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
||||
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
||||
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
|
||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
|
||||
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
||||
@ -620,6 +621,15 @@ mod parse {
|
||||
true
|
||||
}
|
||||
|
||||
crate fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some("panic") => *slot = OomStrategy::Panic,
|
||||
Some("abort") => *slot = OomStrategy::Abort,
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some(s) => match s.parse::<RelroLevel>() {
|
||||
@ -1329,6 +1339,8 @@ options! {
|
||||
"prevent automatic injection of the profiler_builtins crate"),
|
||||
normalize_docs: bool = (false, parse_bool, [TRACKED],
|
||||
"normalize associated items in rustdoc when generating documentation"),
|
||||
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
|
||||
"panic strategy for out-of-memory handling"),
|
||||
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
||||
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
|
||||
panic_abort_tests: bool = (false, parse_bool, [TRACKED],
|
||||
|
@ -315,7 +315,21 @@ pub fn take_alloc_error_hook() -> fn(Layout) {
|
||||
}
|
||||
|
||||
fn default_alloc_error_hook(layout: Layout) {
|
||||
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
|
||||
#[cfg(not(bootstrap))]
|
||||
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;
|
||||
}
|
||||
#[cfg(bootstrap)]
|
||||
let __rust_alloc_error_handler_should_panic = 0;
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
|
||||
panic!("memory allocation of {} bytes failed\n", layout.size());
|
||||
} else {
|
||||
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
|
23
src/test/ui/oom_unwind.rs
Normal file
23
src/test/ui/oom_unwind.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// compile-flags: -Z oom=panic
|
||||
// run-pass
|
||||
// no-prefer-dynamic
|
||||
// needs-unwind
|
||||
// only-linux
|
||||
|
||||
#![feature(bench_black_box)]
|
||||
|
||||
use std::hint::black_box;
|
||||
use std::mem::forget;
|
||||
use std::panic::catch_unwind;
|
||||
|
||||
fn main() {
|
||||
let panic = catch_unwind(|| {
|
||||
// This is guaranteed to exceed even the size of the address space
|
||||
for _ in 0..16 {
|
||||
// Truncates to a suitable value for both 32-bit and 64-bit targets.
|
||||
let alloc_size = 0x1000_0000_1000_0000u64 as usize;
|
||||
forget(black_box(vec![0u8; alloc_size]));
|
||||
}
|
||||
});
|
||||
assert!(panic.is_err());
|
||||
}
|
@ -7,7 +7,7 @@ use std::path::Path;
|
||||
|
||||
const ENTRY_LIMIT: usize = 1000;
|
||||
// FIXME: The following limits should be reduced eventually.
|
||||
const ROOT_ENTRY_LIMIT: usize = 983;
|
||||
const ROOT_ENTRY_LIMIT: usize = 984;
|
||||
const ISSUES_ENTRY_LIMIT: usize = 2310;
|
||||
|
||||
fn check_entries(path: &Path, bad: &mut bool) {
|
||||
|
Loading…
Reference in New Issue
Block a user