Skip to content

Commit aa36237

Browse files
committed
Add -Z oom={panic,abort} command-line option
1 parent 1204400 commit aa36237

File tree

9 files changed

+113
-10
lines changed

9 files changed

+113
-10
lines changed

compiler/rustc_codegen_cranelift/src/allocator.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use crate::prelude::*;
55

66
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
7+
use rustc_session::config::OomStrategy;
78

89
/// Returns whether an allocator shim was created
910
pub(crate) fn codegen(
@@ -18,7 +19,13 @@ pub(crate) fn codegen(
1819
if any_dynamic_crate {
1920
false
2021
} else if let Some(kind) = tcx.allocator_kind(()) {
21-
codegen_inner(module, unwind_context, kind, tcx.lang_items().oom().is_some());
22+
codegen_inner(
23+
module,
24+
unwind_context,
25+
kind,
26+
tcx.lang_items().oom().is_some(),
27+
tcx.sess.opts.debugging_opts.oom,
28+
);
2229
true
2330
} else {
2431
false
@@ -30,6 +37,7 @@ fn codegen_inner(
3037
unwind_context: &mut UnwindContext,
3138
kind: AllocatorKind,
3239
has_alloc_error_handler: bool,
40+
oom_strategy: OomStrategy,
3341
) {
3442
let usize_ty = module.target_config().pointer_type();
3543

@@ -129,4 +137,11 @@ fn codegen_inner(
129137
}
130138
module.define_function(func_id, &mut ctx).unwrap();
131139
unwind_context.add_function(func_id, &ctx, module.isa());
140+
141+
let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
142+
let mut data_ctx = DataContext::new();
143+
data_ctx.set_align(1);
144+
let val = oom_strategy.should_panic();
145+
data_ctx.define(Box::new([val]));
146+
module.define_data(data_id, &data_ctx).unwrap();
132147
}

compiler/rustc_codegen_gcc/src/allocator.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use gccjit::{FunctionType, ToRValue};
1+
use gccjit::{FunctionType, GlobalKind, ToRValue};
22
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
33
use rustc_middle::bug;
44
use rustc_middle::ty::TyCtxt;
5+
use rustc_session::config::OomStrategy;
56
use rustc_span::symbol::sym;
67

78
use crate::GccContext;
@@ -113,4 +114,10 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
113114
let _ret = context.new_call(None, callee, &args);
114115
//llvm::LLVMSetTailCall(ret, True);
115116
block.end_with_void_return(None);
117+
118+
let name = OomStrategy::SYMBOL.to_string();
119+
let global = context.new_global(None, GlobalKind::Exported, i8, name);
120+
let value = tcx.sess.opts.debugging_opts.oom.should_panic();
121+
let value = context.new_rvalue_from_int(i8, value as i32);
122+
global.global_set_initializer_rvalue(value);
116123
}

compiler/rustc_codegen_llvm/src/allocator.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use libc::c_uint;
33
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
44
use rustc_middle::bug;
55
use rustc_middle::ty::TyCtxt;
6-
use rustc_session::config::DebugInfo;
6+
use rustc_session::config::{DebugInfo, OomStrategy};
77
use rustc_span::symbol::sym;
88

99
use crate::debuginfo;
@@ -136,6 +136,16 @@ pub(crate) unsafe fn codegen(
136136
llvm::LLVMBuildRetVoid(llbuilder);
137137
llvm::LLVMDisposeBuilder(llbuilder);
138138

139+
// __rust_alloc_error_handler_should_panic
140+
let name = OomStrategy::SYMBOL;
141+
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
142+
if tcx.sess.target.default_hidden_visibility {
143+
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
144+
}
145+
let val = tcx.sess.opts.debugging_opts.oom.should_panic();
146+
let llval = llvm::LLVMConstInt(i8, val as u64, False);
147+
llvm::LLVMSetInitializer(ll_g, llval);
148+
139149
if tcx.sess.opts.debuginfo != DebugInfo::None {
140150
let dbg_cx = debuginfo::CrateDebugContext::new(llmod);
141151
debuginfo::metadata::compile_unit_metadata(tcx, module_name, &dbg_cx);

compiler/rustc_interface/src/tests.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rustc_session::config::{
99
rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
1010
};
1111
use rustc_session::config::{
12-
BranchProtection, Externs, OutputType, OutputTypes, PAuthKey, PacRet, SymbolManglingVersion,
13-
WasiExecModel,
12+
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
13+
SymbolManglingVersion, WasiExecModel,
1414
};
1515
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
1616
use rustc_session::lint::Level;
@@ -755,6 +755,7 @@ fn test_debugging_options_tracking_hash() {
755755
tracked!(no_link, true);
756756
tracked!(no_unique_section_names, true);
757757
tracked!(no_profiler_runtime, true);
758+
tracked!(oom, OomStrategy::Panic);
758759
tracked!(osx_rpath_install_name, true);
759760
tracked!(panic_abort_tests, true);
760761
tracked!(panic_in_drop, PanicStrategy::Abort);

compiler/rustc_session/src/config.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -2735,9 +2735,9 @@ impl PpMode {
27352735
crate mod dep_tracking {
27362736
use super::{
27372737
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2738-
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType,
2739-
OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion,
2740-
TrimmedDefPaths,
2738+
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2739+
OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
2740+
SymbolManglingVersion, TrimmedDefPaths,
27412741
};
27422742
use crate::lint;
27432743
use crate::options::WasiExecModel;
@@ -2833,6 +2833,7 @@ crate mod dep_tracking {
28332833
RealFileName,
28342834
LocationDetail,
28352835
BranchProtection,
2836+
OomStrategy,
28362837
);
28372838

28382839
impl<T1, T2> DepTrackingHash for (T1, T2)
@@ -2922,3 +2923,24 @@ crate mod dep_tracking {
29222923
}
29232924
}
29242925
}
2926+
2927+
/// Default behavior to use in out-of-memory situations.
2928+
#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2929+
pub enum OomStrategy {
2930+
/// Generate a panic that can be caught by `catch_unwind`.
2931+
Panic,
2932+
2933+
/// Abort the process immediately.
2934+
Abort,
2935+
}
2936+
2937+
impl OomStrategy {
2938+
pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2939+
2940+
pub fn should_panic(self) -> u8 {
2941+
match self {
2942+
OomStrategy::Panic => 1,
2943+
OomStrategy::Abort => 0,
2944+
}
2945+
}
2946+
}

compiler/rustc_session/src/options.rs

+12
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ mod desc {
375375
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
376376
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
377377
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
378+
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
378379
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
379380
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`";
380381
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
@@ -620,6 +621,15 @@ mod parse {
620621
true
621622
}
622623

624+
crate fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
625+
match v {
626+
Some("panic") => *slot = OomStrategy::Panic,
627+
Some("abort") => *slot = OomStrategy::Abort,
628+
_ => return false,
629+
}
630+
true
631+
}
632+
623633
crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
624634
match v {
625635
Some(s) => match s.parse::<RelroLevel>() {
@@ -1328,6 +1338,8 @@ options! {
13281338
"prevent automatic injection of the profiler_builtins crate"),
13291339
normalize_docs: bool = (false, parse_bool, [TRACKED],
13301340
"normalize associated items in rustdoc when generating documentation"),
1341+
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
1342+
"panic strategy for out-of-memory handling"),
13311343
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
13321344
"pass `-install_name @rpath/...` to the macOS linker (default: no)"),
13331345
panic_abort_tests: bool = (false, parse_bool, [TRACKED],

library/std/src/alloc.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,21 @@ pub fn take_alloc_error_hook() -> fn(Layout) {
315315
}
316316

317317
fn default_alloc_error_hook(layout: Layout) {
318-
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
318+
#[cfg(not(bootstrap))]
319+
extern "Rust" {
320+
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
321+
// Its value depends on the -Zoom={panic,abort} compiler option.
322+
static __rust_alloc_error_handler_should_panic: u8;
323+
}
324+
#[cfg(bootstrap)]
325+
let __rust_alloc_error_handler_should_panic = 0;
326+
327+
#[allow(unused_unsafe)]
328+
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
329+
panic!("memory allocation of {} bytes failed\n", layout.size());
330+
} else {
331+
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
332+
}
319333
}
320334

321335
#[cfg(not(test))]

src/test/ui/oom_unwind.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// compile-flags: -Z oom=panic
2+
// run-pass
3+
// no-prefer-dynamic
4+
// needs-unwind
5+
6+
#![feature(bench_black_box)]
7+
8+
use std::hint::black_box;
9+
use std::mem::forget;
10+
use std::panic::catch_unwind;
11+
12+
fn main() {
13+
let panic = catch_unwind(|| {
14+
// This is guaranteed to exceed even the size of the address space
15+
for _ in 0..16 {
16+
// Truncates to a suitable value for both 32-bit and 64-bit targets.
17+
let alloc_size = 0x1000_0000_1000_0000u64 as usize;
18+
forget(black_box(vec![0u8; alloc_size]));
19+
}
20+
});
21+
assert!(panic.is_err());
22+
}

src/tools/tidy/src/ui_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::path::Path;
77

88
const ENTRY_LIMIT: usize = 1000;
99
// FIXME: The following limits should be reduced eventually.
10-
const ROOT_ENTRY_LIMIT: usize = 983;
10+
const ROOT_ENTRY_LIMIT: usize = 984;
1111
const ISSUES_ENTRY_LIMIT: usize = 2310;
1212

1313
fn check_entries(path: &Path, bad: &mut bool) {

0 commit comments

Comments
 (0)