about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2016-02-15 15:45:52 +0100
committerTomasz Miąsko <tomasz.miasko@gmail.com>2016-02-18 08:22:53 +0100
commit77922b817e012989ee8b0f371242e078e58b9ca1 (patch)
treecfb920219a640f6bc4e6dcd2259a7631d04a645f
parent7ce4afbddaa2e58378d8a61a4f6f96dc53acd956 (diff)
downloadrust-77922b817e012989ee8b0f371242e078e58b9ca1.tar.gz
rust-77922b817e012989ee8b0f371242e078e58b9ca1.zip
Remove alternate stack with sigaltstack before unmapping it.
Also reuse existing signal stack if already set, this is especially
useful when working with sanitizers that configure alternate stack
themselves.
m---------src/liblibc0
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs29
-rw-r--r--src/test/run-pass/signal-alternate-stack-cleanup.rs44
3 files changed, 68 insertions, 5 deletions
diff --git a/src/liblibc b/src/liblibc
-Subproject a64ee24718c0289b82a77d692cf56f8a1226de5
+Subproject 403bdc88394919f297bdb365032044cc0481c31
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index a868abbb731..1b5faf64ad6 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -46,7 +46,7 @@ mod imp {
     use super::Handler;
     use mem;
     use ptr;
-    use libc::{sigaltstack, SIGSTKSZ};
+    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
     use libc::{sigaction, SIGBUS, SIG_DFL,
                SA_SIGINFO, SA_ONSTACK, sighandler_t};
     use libc;
@@ -169,13 +169,32 @@ mod imp {
     }
 
     pub unsafe fn make_handler() -> Handler {
-        let stack = get_stack();
-        sigaltstack(&stack, ptr::null_mut());
-        Handler { _data: stack.ss_sp as *mut libc::c_void }
+        let mut stack = mem::zeroed();
+        sigaltstack(ptr::null(), &mut stack);
+        // Configure alternate signal stack, if one is not already set.
+        if stack.ss_flags & SS_DISABLE != 0 {
+            stack = get_stack();
+            sigaltstack(&stack, ptr::null_mut());
+            Handler { _data: stack.ss_sp as *mut libc::c_void }
+        } else {
+            Handler { _data: ptr::null_mut() }
+        }
     }
 
     pub unsafe fn drop_handler(handler: &mut Handler) {
-        munmap(handler._data, SIGSTKSZ);
+        if !handler._data.is_null() {
+            let stack =  libc::stack_t {
+                ss_sp: ptr::null_mut(),
+                ss_flags: SS_DISABLE,
+                // Workaround for bug in MacOS implementation of sigaltstack
+                // UNIX2003 which returns ENOMEM when disabling a stack while
+                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
+                // both ss_sp and ss_size should be ignored in this case.
+                ss_size: SIGSTKSZ,
+            };
+            sigaltstack(&stack, ptr::null_mut());
+            munmap(handler._data, SIGSTKSZ);
+        }
     }
 }
 
diff --git a/src/test/run-pass/signal-alternate-stack-cleanup.rs b/src/test/run-pass/signal-alternate-stack-cleanup.rs
new file mode 100644
index 00000000000..26fa36f0c13
--- /dev/null
+++ b/src/test/run-pass/signal-alternate-stack-cleanup.rs
@@ -0,0 +1,44 @@
+// Copyright 2016 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.
+
+// Previously memory for alternate signal stack have been unmapped during
+// main thread exit while still being in use by signal handlers. This test
+// triggers this situation by sending signal from atexit handler.
+//
+// ignore-windows
+
+#![feature(libc)]
+extern crate libc;
+
+use libc::*;
+
+unsafe extern fn signal_handler(signum: c_int, _: *mut siginfo_t, _: *mut c_void) {
+    assert_eq!(signum, SIGWINCH);
+}
+
+extern fn send_signal() {
+    unsafe {
+        raise(SIGWINCH);
+    }
+}
+
+fn main() {
+    unsafe {
+        // Install signal hander that runs on alternate signal stack.
+        let mut action: sigaction = std::mem::zeroed();
+        action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+        action.sa_sigaction = signal_handler as sighandler_t;
+        sigaction(SIGWINCH, &action, std::ptr::null_mut());
+
+        // Send SIGWINCH on exit.
+        atexit(send_signal);
+    }
+}
+