Skip to content

Commit 8dfb339

Browse files
committed
Auto merge of #105997 - RalfJung:immediate-abort, r=eholk
abort immediately on bad mem::zeroed/uninit Now that we have non-unwinding panics, let's use them for these assertions. This re-establishes the property that `mem::uninitialized` and `mem::zeroed` will never unwind -- the earlier approach of causing panics here sometimes led to hard-to-debug segfaults when the surrounding code was not able to cope with the unexpected unwinding. Cc `@bjorn3` I did not touch cranelift but I assume it needs a similar patch. However it has a `codegen_panic` abstraction that I did not want to touch since I didn't know how else it is used.
2 parents 298d763 + c1b443d commit 8dfb339

File tree

10 files changed

+65
-42
lines changed

10 files changed

+65
-42
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
637637
self.set_debug_loc(bx, terminator.source_info);
638638

639639
// Obtain the panic entry point.
640-
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicNoUnwind);
640+
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
641641

642642
// Codegen the actual panic invoke/call.
643643
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &[], None, None, &[], false);
@@ -698,19 +698,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
698698
})
699699
});
700700
let msg = bx.const_str(&msg_str);
701-
let location = self.get_caller_location(bx, source_info).immediate();
702701

703702
// Obtain the panic entry point.
704703
let (fn_abi, llfn) =
705-
common::build_langcall(bx, Some(source_info.span), LangItem::Panic);
704+
common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
706705

707706
// Codegen the actual panic invoke/call.
708707
helper.do_call(
709708
self,
710709
bx,
711710
fn_abi,
712711
llfn,
713-
&[msg.0, msg.1, location],
712+
&[msg.0, msg.1],
714713
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
715714
cleanup,
716715
&[],
@@ -1665,7 +1664,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16651664
let llpersonality = self.cx.eh_personality();
16661665
bx.cleanup_landing_pad(llpersonality);
16671666

1668-
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicNoUnwind);
1667+
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
16691668
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
16701669

16711670
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], None);

compiler/rustc_hir/src/lang_items.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
146146
}
147147

148148
language_item_table! {
149-
// Variant name, Name, Method name, Target Generic requirements;
149+
// Variant name, Name, Getter method name, Target Generic requirements;
150150
Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
151151
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
152152
/// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
@@ -232,14 +232,15 @@ language_item_table! {
232232
// is required to define it somewhere. Additionally, there are restrictions on crates that use
233233
// a weak lang item, but do not have it defined.
234234
Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
235+
PanicNounwind, sym::panic_nounwind, panic_nounwind, Target::Fn, GenericRequirement::Exact(0);
235236
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
236237
PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None;
237238
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
238239
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
239240
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
240241
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
241242
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
242-
PanicNoUnwind, sym::panic_no_unwind, panic_no_unwind, Target::Fn, GenericRequirement::Exact(0);
243+
PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
243244
/// libstd panic entry point. Necessary for const eval to be able to catch it
244245
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
245246

compiler/rustc_monomorphize/src/collector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
843843
mir::TerminatorKind::Abort { .. } => {
844844
let instance = Instance::mono(
845845
tcx,
846-
tcx.require_lang_item(LangItem::PanicNoUnwind, Some(source)),
846+
tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)),
847847
);
848848
if should_codegen_locally(tcx, &instance) {
849849
self.output.push(create_fn_mono_item(tcx, instance, source));

compiler/rustc_span/src/symbol.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1041,14 +1041,15 @@ symbols! {
10411041
panic_2021,
10421042
panic_abort,
10431043
panic_bounds_check,
1044+
panic_cannot_unwind,
10441045
panic_display,
10451046
panic_fmt,
10461047
panic_handler,
10471048
panic_impl,
10481049
panic_implementation,
10491050
panic_info,
10501051
panic_location,
1051-
panic_no_unwind,
1052+
panic_nounwind,
10521053
panic_runtime,
10531054
panic_str,
10541055
panic_unwind,

library/core/src/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2281,7 +2281,7 @@ macro_rules! assert_unsafe_precondition {
22812281
fn runtime$(<$($tt)*>)?($($i:$ty),*) {
22822282
if !$e {
22832283
// don't unwind to reduce impact on code size
2284-
::core::panicking::panic_str_nounwind(
2284+
::core::panicking::panic_nounwind(
22852285
concat!("unsafe precondition(s) violated: ", $name)
22862286
);
22872287
}

library/core/src/panicking.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,13 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
6464
unsafe { panic_impl(&pi) }
6565
}
6666

67-
/// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize.
68-
/// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed.
67+
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
68+
/// (No `fmt` variant as a `fmt::Arguments` needs more space to be passed.)
6969
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
7070
#[cfg_attr(feature = "panic_immediate_abort", inline)]
71+
#[cfg_attr(not(bootstrap), lang = "panic_nounwind")] // needed by codegen for non-unwinding panics
7172
#[rustc_nounwind]
72-
pub fn panic_str_nounwind(msg: &'static str) -> ! {
73+
pub fn panic_nounwind(msg: &'static str) -> ! {
7374
if cfg!(feature = "panic_immediate_abort") {
7475
super::intrinsics::abort()
7576
}
@@ -153,10 +154,11 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
153154
/// any extra arguments (including those synthesized by track_caller).
154155
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
155156
#[cfg_attr(feature = "panic_immediate_abort", inline)]
156-
#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
157+
#[cfg_attr(bootstrap, lang = "panic_no_unwind")] // needed by codegen for panic in nounwind function
158+
#[cfg_attr(not(bootstrap), lang = "panic_cannot_unwind")] // needed by codegen for panic in nounwind function
157159
#[rustc_nounwind]
158-
fn panic_no_unwind() -> ! {
159-
panic_str_nounwind("panic in a function that cannot unwind")
160+
fn panic_cannot_unwind() -> ! {
161+
panic_nounwind("panic in a function that cannot unwind")
160162
}
161163

162164
/// This function is used instead of panic_fmt in const eval.

src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#[no_mangle]
1111
pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() {
1212
// Handle both legacy and v0 symbol mangling.
13-
// CHECK: call void @{{.*core9panicking15panic_no_unwind}}
13+
// CHECK: call void @{{.*core9panicking19panic_cannot_unwind}}
1414
may_unwind();
1515
}
1616

src/test/codegen/unwind-and-panic-abort.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extern "C-unwind" {
1010
// CHECK: Function Attrs:{{.*}}nounwind
1111
// CHECK-NEXT: define{{.*}}void @foo
1212
// Handle both legacy and v0 symbol mangling.
13-
// CHECK: call void @{{.*core9panicking15panic_no_unwind}}
13+
// CHECK: call void @{{.*core9panicking19panic_cannot_unwind}}
1414
#[no_mangle]
1515
pub unsafe extern "C" fn foo() {
1616
bar();

src/test/codegen/vec-shrink-panik.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ pub fn shrink_to_fit(vec: &mut Vec<u32>) {
1818
pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> {
1919
// CHECK-NOT: panic
2020

21-
// Call to panic_no_unwind in case of double-panic is expected,
21+
// Call to panic_cannot_unwind in case of double-panic is expected,
2222
// but other panics are not.
2323
// CHECK: cleanup
24-
// CHECK-NEXT: ; call core::panicking::panic_no_unwind
25-
// CHECK-NEXT: panic_no_unwind
24+
// CHECK-NEXT: ; call core::panicking::panic_cannot_unwind
25+
// CHECK-NEXT: panic_cannot_unwind
2626

2727
// CHECK-NOT: panic
2828
vec.into_boxed_slice()
@@ -33,15 +33,15 @@ pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> {
3333
pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> {
3434
// CHECK-NOT: panic
3535

36-
// Call to panic_no_unwind in case of double-panic is expected,
36+
// Call to panic_cannot_unwind in case of double-panic is expected,
3737
// but other panics are not.
3838
// CHECK: cleanup
39-
// CHECK-NEXT: ; call core::panicking::panic_no_unwind
40-
// CHECK-NEXT: panic_no_unwind
39+
// CHECK-NEXT: ; call core::panicking::panic_cannot_unwind
40+
// CHECK-NEXT: panic_cannot_unwind
4141

4242
// CHECK-NOT: panic
4343
iter.iter().copied().collect()
4444
}
4545

46-
// CHECK: ; core::panicking::panic_no_unwind
47-
// CHECK: declare void @{{.*}}panic_no_unwind
46+
// CHECK: ; core::panicking::panic_cannot_unwind
47+
// CHECK: declare void @{{.*}}panic_cannot_unwind

src/test/ui/intrinsics/panic-uninitialized-zeroed.rs

+36-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// run-pass
2-
// needs-unwind
3-
// revisions: mir thir strict
4-
// [thir]compile-flags: -Zthir-unsafeck
2+
// revisions: default strict
53
// [strict]compile-flags: -Zstrict-init-checks
64
// ignore-tidy-linelength
5+
// ignore-emscripten spawning processes is not supported
6+
// ignore-sgx no processes
77

88
// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
99

@@ -12,7 +12,6 @@
1212

1313
use std::{
1414
mem::{self, MaybeUninit, ManuallyDrop},
15-
panic,
1615
ptr::NonNull,
1716
num,
1817
};
@@ -70,21 +69,42 @@ enum ZeroIsValid {
7069
}
7170

7271
#[track_caller]
73-
fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
74-
let err = panic::catch_unwind(op).err();
75-
assert_eq!(
76-
err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
77-
Some(&msg)
78-
);
72+
fn test_panic_msg<T, F: (FnOnce() -> T) + 'static>(op: F, msg: &str) {
73+
use std::{panic, env, process};
74+
75+
// The tricky part is that we can't just run `op`, as that would *abort* the process.
76+
// So instead, we reinvoke this process with the caller location as argument.
77+
// For the purpose of this test, the line number is unique enough.
78+
// If we are running in such a re-invocation, we skip all the tests *except* for the one with that type name.
79+
let our_loc = panic::Location::caller().line().to_string();
80+
let mut args = env::args();
81+
let this = args.next().unwrap();
82+
if let Some(loc) = args.next() {
83+
if loc == our_loc {
84+
op();
85+
panic!("we did not abort");
86+
} else {
87+
// Nothing, we are running another test.
88+
}
89+
} else {
90+
// Invoke new process for actual test, and check result.
91+
let mut cmd = process::Command::new(this);
92+
cmd.arg(our_loc);
93+
let res = cmd.output().unwrap();
94+
assert!(!res.status.success(), "test did not fail");
95+
let stderr = String::from_utf8_lossy(&res.stderr);
96+
assert!(stderr.contains(msg), "test did not contain expected output: looking for {:?}, output:\n{}", msg, stderr);
97+
}
7998
}
8099

81100
#[track_caller]
82-
fn test_panic_msg_only_if_strict<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
83-
let err = panic::catch_unwind(op).err();
84-
assert_eq!(
85-
err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
86-
if cfg!(strict) { Some(&msg) } else { None },
87-
);
101+
fn test_panic_msg_only_if_strict<T>(op: impl (FnOnce() -> T) + 'static, msg: &str) {
102+
if !cfg!(strict) {
103+
// Just run it.
104+
op();
105+
} else {
106+
test_panic_msg(op, msg);
107+
}
88108
}
89109

90110
fn main() {

0 commit comments

Comments
 (0)