std: Be resilient to failure in pthread_getattr_np

This can fail on linux for various reasons, such as the /proc filesystem not
being mounted. There are already many cases where we can't set up stack guards,
so just don't worry about this case and communicate that no guard was enabled.

I've confirmed that this allows the compiler to run in a chroot without /proc
mounted.

Closes #22642
This commit is contained in:
Alex Crichton
2015-07-16 11:59:53 -07:00
parent 39d4faf989
commit d68b152c3e
4 changed files with 62 additions and 49 deletions

View File

@@ -96,7 +96,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
// own fault handlers if we hit it. // own fault handlers if we hit it.
sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom,
my_stack_top); my_stack_top);
sys::thread::guard::init(); let main_guard = sys::thread::guard::init();
sys::stack_overflow::init(); sys::stack_overflow::init();
// Next, set up the current Thread with the guard information we just // Next, set up the current Thread with the guard information we just
@@ -104,7 +104,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
// but we just do this to name the main thread and to give it correct // but we just do this to name the main thread and to give it correct
// info about the stack bounds. // info about the stack bounds.
let thread: Thread = NewThread::new(Some("<main>".to_string())); let thread: Thread = NewThread::new(Some("<main>".to_string()));
thread_info::set(sys::thread::guard::main(), thread); thread_info::set(main_guard, thread);
// By default, some platforms will send a *signal* when a EPIPE error // By default, some platforms will send a *signal* when a EPIPE error
// would otherwise be delivered. This runtime doesn't install a SIGPIPE // would otherwise be delivered. This runtime doesn't install a SIGPIPE

View File

@@ -18,7 +18,7 @@ use thread::Thread;
use thread::LocalKeyState; use thread::LocalKeyState;
struct ThreadInfo { struct ThreadInfo {
stack_guard: usize, stack_guard: Option<usize>,
thread: Thread, thread: Thread,
} }
@@ -33,7 +33,7 @@ impl ThreadInfo {
THREAD_INFO.with(move |c| { THREAD_INFO.with(move |c| {
if c.borrow().is_none() { if c.borrow().is_none() {
*c.borrow_mut() = Some(ThreadInfo { *c.borrow_mut() = Some(ThreadInfo {
stack_guard: 0, stack_guard: None,
thread: NewThread::new(None), thread: NewThread::new(None),
}) })
} }
@@ -47,10 +47,10 @@ pub fn current_thread() -> Option<Thread> {
} }
pub fn stack_guard() -> Option<usize> { pub fn stack_guard() -> Option<usize> {
ThreadInfo::with(|info| info.stack_guard) ThreadInfo::with(|info| info.stack_guard).and_then(|o| o)
} }
pub fn set(stack_guard: usize, thread: Thread) { pub fn set(stack_guard: Option<usize>, thread: Thread) {
THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
stack_guard: stack_guard, stack_guard: stack_guard,

View File

@@ -166,9 +166,10 @@ impl Drop for Thread {
not(target_os = "netbsd"), not(target_os = "netbsd"),
not(target_os = "openbsd")))] not(target_os = "openbsd")))]
pub mod guard { pub mod guard {
pub unsafe fn current() -> usize { 0 } use prelude::v1::*;
pub unsafe fn main() -> usize { 0 }
pub unsafe fn init() {} pub unsafe fn current() -> Option<usize> { None }
pub unsafe fn init() -> Option<usize> { None }
} }
@@ -179,6 +180,8 @@ pub mod guard {
target_os = "openbsd"))] target_os = "openbsd"))]
#[allow(unused_imports)] #[allow(unused_imports)]
pub mod guard { pub mod guard {
use prelude::v1::*;
use libc::{self, pthread_t}; use libc::{self, pthread_t};
use libc::funcs::posix88::mman::mmap; use libc::funcs::posix88::mman::mmap;
use libc::consts::os::posix88::{PROT_NONE, use libc::consts::os::posix88::{PROT_NONE,
@@ -191,31 +194,38 @@ pub mod guard {
use super::{pthread_self, pthread_attr_destroy}; use super::{pthread_self, pthread_attr_destroy};
use sys::os; use sys::os;
// These are initialized in init() and only read from after
static mut GUARD_PAGE: usize = 0;
#[cfg(any(target_os = "macos", #[cfg(any(target_os = "macos",
target_os = "bitrig", target_os = "bitrig",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd"))] target_os = "openbsd"))]
unsafe fn get_stack_start() -> *mut libc::c_void { unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
current() as *mut libc::c_void current().map(|s| s as *mut libc::c_void)
} }
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
unsafe fn get_stack_start() -> *mut libc::c_void { unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
use super::pthread_attr_init;
let mut ret = None;
let mut attr: libc::pthread_attr_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed();
assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); assert_eq!(pthread_attr_init(&mut attr), 0);
if pthread_getattr_np(pthread_self(), &mut attr) == 0 {
let mut stackaddr = ptr::null_mut(); let mut stackaddr = ptr::null_mut();
let mut stacksize = 0; let mut stacksize = 0;
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr,
&mut stacksize), 0);
ret = Some(stackaddr);
}
assert_eq!(pthread_attr_destroy(&mut attr), 0); assert_eq!(pthread_attr_destroy(&mut attr), 0);
stackaddr ret
} }
pub unsafe fn init() { pub unsafe fn init() -> Option<usize> {
let psize = os::page_size(); let psize = os::page_size();
let mut stackaddr = get_stack_start(); let mut stackaddr = match get_stack_start() {
Some(addr) => addr,
None => return None,
};
// Ensure stackaddr is page aligned! A parent process might // Ensure stackaddr is page aligned! A parent process might
// have reset RLIMIT_STACK to be non-page aligned. The // have reset RLIMIT_STACK to be non-page aligned. The
@@ -245,25 +255,21 @@ pub mod guard {
let offset = if cfg!(target_os = "linux") {2} else {1}; let offset = if cfg!(target_os = "linux") {2} else {1};
GUARD_PAGE = stackaddr as usize + offset * psize; Some(stackaddr as usize + offset * psize)
}
pub unsafe fn main() -> usize {
GUARD_PAGE
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub unsafe fn current() -> usize { pub unsafe fn current() -> Option<usize> {
extern { extern {
fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void; fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t; fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
} }
(pthread_get_stackaddr_np(pthread_self()) as libc::size_t - Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
pthread_get_stacksize_np(pthread_self())) as usize pthread_get_stacksize_np(pthread_self())) as usize)
} }
#[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))] #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))]
pub unsafe fn current() -> usize { pub unsafe fn current() -> Option<usize> {
#[repr(C)] #[repr(C)]
struct stack_t { struct stack_t {
ss_sp: *mut libc::c_void, ss_sp: *mut libc::c_void,
@@ -280,19 +286,23 @@ pub mod guard {
assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0); assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);
let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
if pthread_main_np() == 1 { Some(if pthread_main_np() == 1 {
// main thread // main thread
current_stack.ss_sp as usize - current_stack.ss_size as usize + extra current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
} else { } else {
// new thread // new thread
current_stack.ss_sp as usize - current_stack.ss_size as usize current_stack.ss_sp as usize - current_stack.ss_size as usize
} })
} }
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
pub unsafe fn current() -> usize { pub unsafe fn current() -> Option<usize> {
use super::pthread_attr_init;
let mut ret = None;
let mut attr: libc::pthread_attr_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed();
assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); assert_eq!(pthread_attr_init(&mut attr), 0);
if pthread_getattr_np(pthread_self(), &mut attr) == 0 {
let mut guardsize = 0; let mut guardsize = 0;
assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
if guardsize == 0 { if guardsize == 0 {
@@ -301,9 +311,11 @@ pub mod guard {
let mut stackaddr = ptr::null_mut(); let mut stackaddr = ptr::null_mut();
let mut size = 0; let mut size = 0;
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
assert_eq!(pthread_attr_destroy(&mut attr), 0);
stackaddr as usize + guardsize as usize ret = Some(stackaddr as usize + guardsize as usize);
}
assert_eq!(pthread_attr_destroy(&mut attr), 0);
return ret
} }
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]

View File

@@ -86,7 +86,8 @@ impl Thread {
} }
pub mod guard { pub mod guard {
pub unsafe fn main() -> usize { 0 } use prelude::v1::*;
pub unsafe fn current() -> usize { 0 }
pub unsafe fn init() {} pub unsafe fn current() -> Option<usize> { None }
pub unsafe fn init() -> Option<usize> { None }
} }