Skip to content

Commit e997086

Browse files
committed
std: make stack guard page location available during TLS destruction
1 parent 15c7965 commit e997086

File tree

3 files changed

+34
-38
lines changed

3 files changed

+34
-38
lines changed

library/std/src/sys/unix/stack_overflow.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ mod imp {
4242
use crate::io;
4343
use crate::mem;
4444
use crate::ptr;
45-
use crate::thread;
45+
use crate::sys_common::thread_info::current_thread;
4646

4747
use libc::MAP_FAILED;
4848
#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
@@ -89,10 +89,9 @@ mod imp {
8989
// If the faulting address is within the guard page, then we print a
9090
// message saying so and abort.
9191
if guard.start <= addr && addr < guard.end {
92-
rtprintpanic!(
93-
"\nthread '{}' has overflowed its stack\n",
94-
thread::current().name().unwrap_or("<unknown>")
95-
);
92+
let thread = current_thread();
93+
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unknown>");
94+
rtprintpanic!("\nthread '{}' has overflowed its stack\n", name);
9695
rtabort!("stack overflow");
9796
} else {
9897
// Unregister ourselves by reverting back to the default behavior.
Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,41 @@
11
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
2-
#![allow(unused_unsafe)] // thread_local with `const {}` triggers this liny
32

4-
use crate::cell::RefCell;
3+
use crate::cell::Cell;
54
use crate::sys::thread::guard::Guard;
65
use crate::thread::Thread;
76

8-
struct ThreadInfo {
9-
stack_guard: Option<Guard>,
10-
thread: Thread,
11-
}
12-
13-
thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = const { RefCell::new(None) } }
14-
15-
impl ThreadInfo {
16-
fn with<R, F>(f: F) -> Option<R>
17-
where
18-
F: FnOnce(&mut ThreadInfo) -> R,
19-
{
20-
THREAD_INFO
21-
.try_with(move |thread_info| {
22-
let mut thread_info = thread_info.borrow_mut();
23-
let thread_info = thread_info.get_or_insert_with(|| ThreadInfo {
24-
stack_guard: None,
25-
thread: Thread::new(None),
26-
});
27-
f(thread_info)
28-
})
29-
.ok()
30-
}
7+
thread_local! {
8+
static THREAD: Cell<Option<Thread>> = const { Cell::new(None) };
9+
// Use a separate thread local for the stack guard page location.
10+
// Since `Guard` does not implement drop, this is always available
11+
// on systems with ELF-TLS, in particular during TLS destruction.
12+
static STACK_GUARD: Cell<Option<Guard>> = const { Cell::new(None) };
3113
}
3214

3315
pub fn current_thread() -> Option<Thread> {
34-
ThreadInfo::with(|info| info.thread.clone())
16+
THREAD
17+
.try_with(|thread| {
18+
let t = thread.take().unwrap_or_else(|| Thread::new(None));
19+
let t2 = t.clone();
20+
thread.set(Some(t));
21+
t2
22+
})
23+
.ok()
3524
}
3625

3726
pub fn stack_guard() -> Option<Guard> {
38-
ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
27+
STACK_GUARD
28+
.try_with(|guard| {
29+
let g = guard.take();
30+
let g2 = g.clone();
31+
guard.set(g);
32+
g2
33+
})
34+
.ok()
35+
.flatten()
3936
}
4037

4138
pub fn set(stack_guard: Option<Guard>, thread: Thread) {
42-
THREAD_INFO.with(move |thread_info| {
43-
let mut thread_info = thread_info.borrow_mut();
44-
rtassert!(thread_info.is_none());
45-
*thread_info = Some(ThreadInfo { stack_guard, thread });
46-
});
39+
rtassert!(STACK_GUARD.replace(stack_guard).is_none());
40+
rtassert!(THREAD.replace(Some(thread)).is_none());
4741
}

tests/ui/abi/stack-probes.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ fn main() {
4444
// details
4545
if cfg!(not(target_os = "linux")) {
4646
assert_overflow(Command::new(&me).arg("main-recurse"));
47-
assert_overflow(Command::new(&me).arg("main-tls-recurse"));
47+
// FIXME: This does not seem to work on macOS.
48+
if cfg!(not(target_os = "macos")) {
49+
assert_overflow(Command::new(&me).arg("main-tls-recurse"));
50+
}
4851
}
4952
assert_overflow(Command::new(&me).arg("child-recurse"));
5053
assert_overflow(Command::new(&me).arg("child-tls-recurse"));

0 commit comments

Comments
 (0)