Skip to content

Commit

Permalink
std: Be resilient to failure in pthread_getattr_np
Browse files Browse the repository at this point in the history
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
  • Loading branch information
alexcrichton committed Jul 21, 2015
1 parent 39d4faf commit d68b152
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 47 deletions.
4 changes: 2 additions & 2 deletions src/libstd/rt/mod.rs
Expand Up @@ -96,15 +96,15 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
// own fault handlers if we hit it.
sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom,
my_stack_top);
sys::thread::guard::init();
let main_guard = sys::thread::guard::init();
sys::stack_overflow::init();

// Next, set up the current Thread with the guard information we just
// created. Note that this isn't necessary in general for new threads,
// but we just do this to name the main thread and to give it correct
// info about the stack bounds.
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
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
Expand Down
8 changes: 4 additions & 4 deletions src/libstd/sys/common/thread_info.rs
Expand Up @@ -18,7 +18,7 @@ use thread::Thread;
use thread::LocalKeyState;

struct ThreadInfo {
stack_guard: usize,
stack_guard: Option<usize>,
thread: Thread,
}

Expand All @@ -33,7 +33,7 @@ impl ThreadInfo {
THREAD_INFO.with(move |c| {
if c.borrow().is_none() {
*c.borrow_mut() = Some(ThreadInfo {
stack_guard: 0,
stack_guard: None,
thread: NewThread::new(None),
})
}
Expand All @@ -47,10 +47,10 @@ pub fn current_thread() -> Option<Thread> {
}

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(move |c| *c.borrow_mut() = Some(ThreadInfo{
stack_guard: stack_guard,
Expand Down
88 changes: 50 additions & 38 deletions src/libstd/sys/unix/thread.rs
Expand Up @@ -166,9 +166,10 @@ impl Drop for Thread {
not(target_os = "netbsd"),
not(target_os = "openbsd")))]
pub mod guard {
pub unsafe fn current() -> usize { 0 }
pub unsafe fn main() -> usize { 0 }
pub unsafe fn init() {}
use prelude::v1::*;

pub unsafe fn current() -> Option<usize> { None }
pub unsafe fn init() -> Option<usize> { None }
}


Expand All @@ -179,6 +180,8 @@ pub mod guard {
target_os = "openbsd"))]
#[allow(unused_imports)]
pub mod guard {
use prelude::v1::*;

use libc::{self, pthread_t};
use libc::funcs::posix88::mman::mmap;
use libc::consts::os::posix88::{PROT_NONE,
Expand All @@ -191,31 +194,38 @@ pub mod guard {
use super::{pthread_self, pthread_attr_destroy};
use sys::os;

// These are initialized in init() and only read from after
static mut GUARD_PAGE: usize = 0;

#[cfg(any(target_os = "macos",
target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd"))]
unsafe fn get_stack_start() -> *mut libc::c_void {
current() as *mut libc::c_void
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
current().map(|s| s as *mut libc::c_void)
}

#[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();
assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
let mut stackaddr = ptr::null_mut();
let mut stacksize = 0;
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 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 stacksize = 0;
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr,
&mut stacksize), 0);
ret = Some(stackaddr);
}
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 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
// have reset RLIMIT_STACK to be non-page aligned. The
Expand Down Expand Up @@ -245,25 +255,21 @@ pub mod guard {

let offset = if cfg!(target_os = "linux") {2} else {1};

GUARD_PAGE = stackaddr as usize + offset * psize;
}

pub unsafe fn main() -> usize {
GUARD_PAGE
Some(stackaddr as usize + offset * psize)
}

#[cfg(target_os = "macos")]
pub unsafe fn current() -> usize {
pub unsafe fn current() -> Option<usize> {
extern {
fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
}
(pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
pthread_get_stacksize_np(pthread_self())) as usize
Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
pthread_get_stacksize_np(pthread_self())) as usize)
}

#[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))]
pub unsafe fn current() -> usize {
pub unsafe fn current() -> Option<usize> {
#[repr(C)]
struct stack_t {
ss_sp: *mut libc::c_void,
Expand All @@ -280,30 +286,36 @@ pub mod guard {
assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);

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
current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
} else {
// new thread
current_stack.ss_sp as usize - current_stack.ss_size as usize
}
})
}

#[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();
assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
let mut guardsize = 0;
assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
if guardsize == 0 {
panic!("there is no guard page");
assert_eq!(pthread_attr_init(&mut attr), 0);
if pthread_getattr_np(pthread_self(), &mut attr) == 0 {
let mut guardsize = 0;
assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
if guardsize == 0 {
panic!("there is no guard page");
}
let mut stackaddr = ptr::null_mut();
let mut size = 0;
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);

ret = Some(stackaddr as usize + guardsize as usize);
}
let mut stackaddr = ptr::null_mut();
let 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
return ret
}

#[cfg(any(target_os = "linux", target_os = "android"))]
Expand Down
7 changes: 4 additions & 3 deletions src/libstd/sys/windows/thread.rs
Expand Up @@ -86,7 +86,8 @@ impl Thread {
}

pub mod guard {
pub unsafe fn main() -> usize { 0 }
pub unsafe fn current() -> usize { 0 }
pub unsafe fn init() {}
use prelude::v1::*;

pub unsafe fn current() -> Option<usize> { None }
pub unsafe fn init() -> Option<usize> { None }
}

0 comments on commit d68b152

Please sign in to comment.