Skip to content

Commit

Permalink
Rollup merge of #83771 - asomers:stack_overflow_freebsd, r=dtolnay
Browse files Browse the repository at this point in the history
Fix stack overflow detection on FreeBSD 11.1+

Beginning with FreeBSD 10.4 and 11.1, there is one guard page by
default.  And the stack autoresizes, so if Rust allocates its own guard
page, then FreeBSD's will simply move up one page.  The best solution is
to just use the OS's guard page.
  • Loading branch information
JohnTitor committed Apr 2, 2021
2 parents 6404a9d + ca14abb commit b98eea4
Showing 1 changed file with 16 additions and 7 deletions.
23 changes: 16 additions & 7 deletions library/std/src/sys/unix/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,20 @@ pub mod guard {
// it can eventually grow to. It cannot be used to determine
// the position of kernel's stack guard.
None
} else if cfg!(target_os = "freebsd") {
// FreeBSD's stack autogrows, and optionally includes a guard page
// at the bottom. If we try to remap the bottom of the stack
// ourselves, FreeBSD's guard page moves upwards. So we'll just use
// the builtin guard page.
let stackaddr = get_stack_start_aligned()?;
let guardaddr = stackaddr as usize;
// Technically the number of guard pages is tunable and controlled
// by the security.bsd.stack_guard_page sysctl, but there are
// few reasons to change it from the default. The default value has
// been 1 ever since FreeBSD 11.1 and 10.4.
const GUARD_PAGES: usize = 1;
let guard = guardaddr..guardaddr + GUARD_PAGES * page_size;
Some(guard)
} else {
// Reallocate the last page of the stack.
// This ensures SIGBUS will be raised on
Expand Down Expand Up @@ -371,9 +385,8 @@ pub mod guard {
}

let guardaddr = stackaddr as usize;
let offset = if cfg!(target_os = "freebsd") { 2 } else { 1 };

Some(guardaddr..guardaddr + offset * page_size)
Some(guardaddr..guardaddr + page_size)
}
}

Expand Down Expand Up @@ -417,11 +430,7 @@ pub mod guard {
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);

let stackaddr = stackaddr as usize;
ret = if cfg!(target_os = "freebsd") {
// FIXME does freebsd really fault *below* the guard addr?
let guardaddr = stackaddr - guardsize;
Some(guardaddr - PAGE_SIZE.load(Ordering::Relaxed)..guardaddr)
} else if cfg!(target_os = "netbsd") {
ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd")) {
Some(stackaddr - guardsize..stackaddr)
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
Some(stackaddr - guardsize..stackaddr)
Expand Down

0 comments on commit b98eea4

Please sign in to comment.