about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2021-04-02 19:57:35 +0200
committerGitHub <noreply@github.com>2021-04-02 19:57:35 +0200
commitcb7133f6934843408b36ce163cf1c3f3596fac68 (patch)
tree081a410167ea3b52f6e2562e20e161691b9993f5
parenteed73c6e4d21e25cd553fe06a24e5200714bc0ab (diff)
parentca14abbab1821d20d4d326af2acec916ccc0806e (diff)
downloadrust-cb7133f6934843408b36ce163cf1c3f3596fac68.tar.gz
rust-cb7133f6934843408b36ce163cf1c3f3596fac68.zip
Rollup merge of #83771 - asomers:stack_overflow_freebsd, r=dtolnay
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.
-rw-r--r--library/std/src/sys/unix/thread.rs23
1 files changed, 16 insertions, 7 deletions
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 01a12dcf5a2..b8f43caec32 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -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
@@ -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)
         }
     }
 
@@ -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)