mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-04 18:08:53 +03:00
55b54a999b
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.
53 lines
1.6 KiB
Rust
53 lines
1.6 KiB
Rust
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
|
// file at the top-level directory of this distribution and at
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
|
|
|
|
use cell::RefCell;
|
|
use sys::thread::guard::Guard;
|
|
use thread::Thread;
|
|
|
|
struct ThreadInfo {
|
|
stack_guard: Option<Guard>,
|
|
thread: Thread,
|
|
}
|
|
|
|
thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(None) }
|
|
|
|
impl ThreadInfo {
|
|
fn with<R, F>(f: F) -> Option<R> where F: FnOnce(&mut ThreadInfo) -> R {
|
|
THREAD_INFO.try_with(move |c| {
|
|
if c.borrow().is_none() {
|
|
*c.borrow_mut() = Some(ThreadInfo {
|
|
stack_guard: None,
|
|
thread: Thread::new(None),
|
|
})
|
|
}
|
|
f(c.borrow_mut().as_mut().unwrap())
|
|
}).ok()
|
|
}
|
|
}
|
|
|
|
pub fn current_thread() -> Option<Thread> {
|
|
ThreadInfo::with(|info| info.thread.clone())
|
|
}
|
|
|
|
pub fn stack_guard() -> Option<Guard> {
|
|
ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
|
|
}
|
|
|
|
pub fn set(stack_guard: Option<Guard>, thread: Thread) {
|
|
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
|
|
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
|
|
stack_guard,
|
|
thread,
|
|
}));
|
|
}
|