Skip to content

Commit a371972

Browse files
committed
Regression tests for issue 64655.
1 parent 9fbb2a9 commit a371972

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// run-pass
2+
3+
// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine
4+
// should still run desstructors as it unwindws the stack. However,
5+
// bugs with how the nounwind LLVM attribute was applied led to this
6+
// simple case being mishandled *if* you had fat LTO turned on.
7+
8+
// Unlike issue-64655-extern-rust-must-allow-unwind.rs, the issue
9+
// embodied in this test cropped up regardless of optimization level.
10+
// Therefore it seemed worthy of being enshrined as a dedicated unit
11+
// test.
12+
13+
// LTO settings cannot be combined with -C prefer-dynamic
14+
// no-prefer-dynamic
15+
16+
// The revisions just enumerate lto settings (the opt-level appeared irrelevant in practice)
17+
18+
// revisions: no thin fat
19+
//[no]compile-flags: -C lto=no
20+
//[thin]compile-flags: -C lto=thin
21+
//[fat]compile-flags: -C lto=fat
22+
23+
#![feature(core_panic)]
24+
25+
// (For some reason, reproducing the LTO issue requires pulling in std
26+
// explicitly this way.)
27+
#![no_std]
28+
extern crate std;
29+
30+
fn main() {
31+
use std::sync::atomic::{AtomicUsize, Ordering};
32+
use std::boxed::Box;
33+
34+
static SHARED: AtomicUsize = AtomicUsize::new(0);
35+
36+
assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0);
37+
38+
let old_hook = std::panic::take_hook();
39+
40+
std::panic::set_hook(Box::new(|_| { } )); // no-op on panic.
41+
42+
let handle = std::thread::spawn(|| {
43+
struct Droppable;
44+
impl Drop for Droppable {
45+
fn drop(&mut self) {
46+
SHARED.fetch_add(1, Ordering::SeqCst);
47+
}
48+
}
49+
50+
let _guard = Droppable;
51+
let s = "issue-64655-allow-unwind-when-calling-panic-directly.rs";
52+
core::panicking::panic(&("???", s, 17, 4));
53+
});
54+
55+
let wait = handle.join();
56+
57+
// reinstate handler to ease observation of assertion failures.
58+
std::panic::set_hook(old_hook);
59+
60+
assert!(wait.is_err());
61+
62+
assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1);
63+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// run-pass
2+
3+
// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine
4+
// should still run desstructors as it unwindws the stack. However,
5+
// bugs with how the nounwind LLVM attribute was applied led to this
6+
// simple case being mishandled *if* you had optimization *and* fat
7+
// LTO turned on.
8+
9+
// This test is the closest thing to a "regression test" we can do
10+
// without actually spawning subprocesses and comparing stderr
11+
// results.
12+
//
13+
// This test takes the code from the above issue and adapts it to
14+
// better fit our test infrastructure:
15+
//
16+
// * Instead of relying on println! to observe whether the destructor
17+
// is run, we instead run the code in a spawned thread and
18+
// communicate the destructor's operation via a synchronous atomic
19+
// in static memory.
20+
//
21+
// * To keep the output from confusing a casual user, we override the
22+
// panic hook to be a no-op (rather than printing a message to
23+
// stderr).
24+
//
25+
// (pnkfelix has confirmed by hand that these additions do not mask
26+
// the underlying bug.)
27+
28+
// LTO settings cannot be combined with -C prefer-dynamic
29+
// no-prefer-dynamic
30+
31+
// The revisions combine each lto setting with each optimization
32+
// setting; pnkfelix observed three differing behaviors at opt-levels
33+
// 0/1/2+3 for this test, so it seems prudent to be thorough.
34+
35+
// revisions: no0 no1 no2 no3 thin0 thin1 thin2 thin3 fat0 fat1 fat2 fat3
36+
37+
//[no0]compile-flags: -C opt-level=0 -C lto=no
38+
//[no1]compile-flags: -C opt-level=1 -C lto=no
39+
//[no2]compile-flags: -C opt-level=2 -C lto=no
40+
//[no3]compile-flags: -C opt-level=3 -C lto=no
41+
//[thin0]compile-flags: -C opt-level=0 -C lto=thin
42+
//[thin1]compile-flags: -C opt-level=1 -C lto=thin
43+
//[thin2]compile-flags: -C opt-level=2 -C lto=thin
44+
//[thin3]compile-flags: -C opt-level=3 -C lto=thin
45+
//[fat0]compile-flags: -C opt-level=0 -C lto=fat
46+
//[fat1]compile-flags: -C opt-level=1 -C lto=fat
47+
//[fat2]compile-flags: -C opt-level=2 -C lto=fat
48+
//[fat3]compile-flags: -C opt-level=3 -C lto=fat
49+
50+
fn main() {
51+
use std::sync::atomic::{AtomicUsize, Ordering};
52+
53+
static SHARED: AtomicUsize = AtomicUsize::new(0);
54+
55+
assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0);
56+
57+
let old_hook = std::panic::take_hook();
58+
59+
std::panic::set_hook(Box::new(|_| { } )); // no-op on panic.
60+
61+
let handle = std::thread::spawn(|| {
62+
struct Droppable;
63+
impl Drop for Droppable {
64+
fn drop(&mut self) {
65+
SHARED.fetch_add(1, Ordering::SeqCst);
66+
}
67+
}
68+
69+
let _guard = Droppable;
70+
None::<()>.expect("???");
71+
});
72+
73+
let wait = handle.join();
74+
75+
// reinstate handler to ease observation of assertion failures.
76+
std::panic::set_hook(old_hook);
77+
78+
assert!(wait.is_err());
79+
80+
assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1);
81+
}
82+

0 commit comments

Comments
 (0)