2015-03-09 20:04:35 -07:00
|
|
|
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
|
2021-09-16 14:55:15 +02:00
|
|
|
#![allow(unused_unsafe)] // thread_local with `const {}` triggers this liny
|
2015-03-09 20:04:35 -07:00
|
|
|
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::cell::RefCell;
|
|
|
|
|
use crate::sys::thread::guard::Guard;
|
|
|
|
|
use crate::thread::Thread;
|
2014-12-07 00:32:50 -08:00
|
|
|
|
2014-11-25 08:52:10 -08:00
|
|
|
struct ThreadInfo {
|
Use a range to identify SIGSEGV in stack guards
Previously, the `guard::init()` and `guard::current()` functions were
returning a `usize` address representing the top of the stack guard,
respectively for the main thread and for spawned threads. The `SIGSEGV`
handler on `unix` targets checked if a fault was within one page below
that address, if so reporting it as a stack overflow.
Now `unix` targets report a `Range<usize>` representing the guard
memory, so it can cover arbitrary guard sizes. Non-`unix` targets which
always return `None` for guards now do so with `Option<!>`, so they
don't pay any overhead.
For `linux-gnu` in particular, the previous guard upper-bound was
`stackaddr + guardsize`, as the protected memory was *inside* the stack.
This was a glibc bug, and starting from 2.27 they are moving the guard
*past* the end of the stack. However, there's no simple way for us to
know where the guard page actually lies, so now we declare it as the
whole range of `stackaddr ± guardsize`, and any fault therein will be
called a stack overflow. This fixes #47863.
2018-01-31 11:41:29 -08:00
|
|
|
stack_guard: Option<Guard>,
|
2014-11-25 08:52:10 -08:00
|
|
|
thread: Thread,
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 14:55:15 +02:00
|
|
|
thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = const { RefCell::new(None) } }
|
2014-11-25 08:52:10 -08:00
|
|
|
|
|
|
|
|
impl ThreadInfo {
|
2019-11-27 10:29:00 -08:00
|
|
|
fn with<R, F>(f: F) -> Option<R>
|
|
|
|
|
where
|
|
|
|
|
F: FnOnce(&mut ThreadInfo) -> R,
|
|
|
|
|
{
|
|
|
|
|
THREAD_INFO
|
2021-09-16 14:48:33 +02:00
|
|
|
.try_with(move |thread_info| {
|
|
|
|
|
let mut thread_info = thread_info.borrow_mut();
|
|
|
|
|
let thread_info = thread_info.get_or_insert_with(|| ThreadInfo {
|
|
|
|
|
stack_guard: None,
|
|
|
|
|
thread: Thread::new(None),
|
|
|
|
|
});
|
|
|
|
|
f(thread_info)
|
2019-11-27 10:29:00 -08:00
|
|
|
})
|
|
|
|
|
.ok()
|
2014-11-25 08:52:10 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-15 12:27:05 -07:00
|
|
|
pub fn current_thread() -> Option<Thread> {
|
2014-11-25 08:52:10 -08:00
|
|
|
ThreadInfo::with(|info| info.thread.clone())
|
|
|
|
|
}
|
|
|
|
|
|
Use a range to identify SIGSEGV in stack guards
Previously, the `guard::init()` and `guard::current()` functions were
returning a `usize` address representing the top of the stack guard,
respectively for the main thread and for spawned threads. The `SIGSEGV`
handler on `unix` targets checked if a fault was within one page below
that address, if so reporting it as a stack overflow.
Now `unix` targets report a `Range<usize>` representing the guard
memory, so it can cover arbitrary guard sizes. Non-`unix` targets which
always return `None` for guards now do so with `Option<!>`, so they
don't pay any overhead.
For `linux-gnu` in particular, the previous guard upper-bound was
`stackaddr + guardsize`, as the protected memory was *inside* the stack.
This was a glibc bug, and starting from 2.27 they are moving the guard
*past* the end of the stack. However, there's no simple way for us to
know where the guard page actually lies, so now we declare it as the
whole range of `stackaddr ± guardsize`, and any fault therein will be
called a stack overflow. This fixes #47863.
2018-01-31 11:41:29 -08:00
|
|
|
pub fn stack_guard() -> Option<Guard> {
|
|
|
|
|
ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
|
2014-12-07 00:32:50 -08:00
|
|
|
}
|
|
|
|
|
|
Use a range to identify SIGSEGV in stack guards
Previously, the `guard::init()` and `guard::current()` functions were
returning a `usize` address representing the top of the stack guard,
respectively for the main thread and for spawned threads. The `SIGSEGV`
handler on `unix` targets checked if a fault was within one page below
that address, if so reporting it as a stack overflow.
Now `unix` targets report a `Range<usize>` representing the guard
memory, so it can cover arbitrary guard sizes. Non-`unix` targets which
always return `None` for guards now do so with `Option<!>`, so they
don't pay any overhead.
For `linux-gnu` in particular, the previous guard upper-bound was
`stackaddr + guardsize`, as the protected memory was *inside* the stack.
This was a glibc bug, and starting from 2.27 they are moving the guard
*past* the end of the stack. However, there's no simple way for us to
know where the guard page actually lies, so now we declare it as the
whole range of `stackaddr ± guardsize`, and any fault therein will be
called a stack overflow. This fixes #47863.
2018-01-31 11:41:29 -08:00
|
|
|
pub fn set(stack_guard: Option<Guard>, thread: Thread) {
|
2014-11-25 08:52:10 -08:00
|
|
|
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
|
2019-11-27 10:29:00 -08:00
|
|
|
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo { stack_guard, thread }));
|
2014-11-25 08:52:10 -08:00
|
|
|
}
|