about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-06-22 16:11:38 +0000
committerbors <bors@rust-lang.org>2015-06-22 16:11:38 +0000
commit4e2a898afcd890d44a45bd229dee8b9db8d330cc (patch)
tree8ac7c508782bf1b880c6e7a624025f52e5413e60 /src
parent2287b4b628cb6f4d66578e1298cd9f34e9ef77db (diff)
parenta8dbb92b471cae1d3f8225857f5553311dd8aeb3 (diff)
downloadrust-4e2a898afcd890d44a45bd229dee8b9db8d330cc.tar.gz
rust-4e2a898afcd890d44a45bd229dee8b9db8d330cc.zip
Auto merge of #25784 - geofft:subprocess-signal-masks, r=alexcrichton
UNIX specifies that signal dispositions and masks get inherited to child processes, but in general, programs are not very robust to being started with non-default signal dispositions or to signals being blocked. For example, libstd sets `SIGPIPE` to be ignored, on the grounds that Rust code using libstd will get the `EPIPE` errno and handle it correctly. But shell pipelines are built around the assumption that `SIGPIPE` will have its default behavior of killing the process, so that things like `head` work:

```
geofft@titan:/tmp$ for i in `seq 1 20`; do echo "$i"; done | head -1
1
geofft@titan:/tmp$ cat bash.rs
fn main() {
        std::process::Command::new("bash").status();
}
geofft@titan:/tmp$ ./bash
geofft@titan:/tmp$ for i in `seq 1 20`; do echo "$i"; done | head -1
1
bash: echo: write error: Broken pipe
bash: echo: write error: Broken pipe
bash: echo: write error: Broken pipe
bash: echo: write error: Broken pipe
bash: echo: write error: Broken pipe
[...]
```

Here, `head` is supposed to terminate the input process quietly, but the bash subshell has inherited the ignored disposition of `SIGPIPE` from its Rust grandparent process. So it gets a bunch of `EPIPE`s that it doesn't know what to do with, and treats it as a generic, transient error. You can see similar behavior with `find / | head`, `yes | head`, etc.

This PR resets Rust's `SIGPIPE` handler, as well as any signal mask that may have been set, before spawning a child. Setting a signal mask, and then using a dedicated thread or something like `signalfd` to dequeue signals, is one of two reasonable ways for a library to process signals. See carllerche/mio#16 for more discussion about this approach to signal handling and why it needs a change to `std::process`. The other approach is for the library to set a signal-handling function (`signal()` / `sigaction()`): in that case, dispositions are reset to the default behavior on exec (since the function pointer isn't valid across exec), so we don't have to care about that here.

As part of this PR, I noticed that we had two somewhat-overlapping sets of bindings to signal functionality in `libstd`. One dated to old-IO and probably the old runtime, and was mostly unused. The other is currently used by `stack_overflow.rs`. I consolidated the two bindings into one set, and double-checked them by hand against all supported platforms' headers. This probably means it's safe to enable `stack_overflow.rs` on more targets, but I'm not including such a change in this PR.

r? @alexcrichton
cc @Zoxc for changes to `stack_overflow.rs`
Diffstat (limited to 'src')
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/process.rs18
-rw-r--r--src/libstd/sys/unix/c.rs421
-rw-r--r--src/libstd/sys/unix/process.rs84
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs141
-rw-r--r--src/test/run-pass/process-sigpipe.rs39
6 files changed, 344 insertions, 361 deletions
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index e5242c5bf86..e27e4ba5af2 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -148,8 +148,6 @@
 #![feature(vec_push_all)]
 #![feature(wrapping)]
 #![feature(zero_one)]
-#![cfg_attr(all(unix, not(target_os = "macos"), not(target_os = "ios")),
-            feature(num_bits_bytes))]
 #![cfg_attr(windows, feature(str_utf16))]
 #![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras))]
 #![cfg_attr(test, feature(test, rustc_private, float_consts))]
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index d70b9f09903..a8127b3200f 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -770,24 +770,6 @@ mod tests {
     }
 
     #[cfg(all(unix, not(target_os="android")))]
-    pub fn pwd_cmd() -> Command {
-        Command::new("pwd")
-    }
-    #[cfg(target_os="android")]
-    pub fn pwd_cmd() -> Command {
-        let mut cmd = Command::new("/system/bin/sh");
-        cmd.arg("-c").arg("pwd");
-        cmd
-    }
-
-    #[cfg(windows)]
-    pub fn pwd_cmd() -> Command {
-        let mut cmd = Command::new("cmd");
-        cmd.arg("/c").arg("cd");
-        cmd
-    }
-
-    #[cfg(all(unix, not(target_os="android")))]
     pub fn env_cmd() -> Command {
         Command::new("env")
     }
diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs
index 1e68eac5a67..99a6731c57d 100644
--- a/src/libstd/sys/unix/c.rs
+++ b/src/libstd/sys/unix/c.rs
@@ -8,15 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! C definitions used by libnative that don't belong in liblibc
+//! C definitions used by std::sys that don't belong in liblibc
+
+// These are definitions sufficient for the users in this directory.
+// This is not a general-purpose binding to this functionality, and in
+// some cases (notably the definition of siginfo_t), we intentionally
+// have incomplete bindings so that we don't need to fight with unions.
+//
+// Note that these types need to match the definitions from the platform
+// libc (currently glibc on Linux), not the kernel definitions / the
+// syscall interface.  This has a few weirdnesses, like glibc's sigset_t
+// being 1024 bits on all platforms. If you're adding a new GNU/Linux
+// port, check glibc's sysdeps/unix/sysv/linux, not the kernel headers.
 
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
 
-pub use self::select::fd_set;
-pub use self::signal::{sigaction, siginfo, sigset_t};
-pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP};
-pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};
+pub use self::signal_os::{sigaction, siginfo, sigset_t, sigaltstack};
+pub use self::signal_os::{SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSTKSZ, SIG_SETMASK};
 
 use libc;
 
@@ -26,45 +35,21 @@ use libc;
           target_os = "dragonfly",
           target_os = "bitrig",
           target_os = "openbsd"))]
-mod consts {
-    use libc;
-    pub const FIONBIO: libc::c_ulong = 0x8004667e;
-    pub const FIOCLEX: libc::c_ulong = 0x20006601;
-    pub const FIONCLEX: libc::c_ulong = 0x20006602;
-}
+pub const FIOCLEX: libc::c_ulong = 0x20006601;
+
 #[cfg(any(all(target_os = "linux",
               any(target_arch = "x86",
                   target_arch = "x86_64",
                   target_arch = "arm",
                   target_arch = "aarch64")),
           target_os = "android"))]
-mod consts {
-    use libc;
-    pub const FIONBIO: libc::c_ulong = 0x5421;
-    pub const FIOCLEX: libc::c_ulong = 0x5451;
-    pub const FIONCLEX: libc::c_ulong = 0x5450;
-}
+pub const FIOCLEX: libc::c_ulong = 0x5451;
+
 #[cfg(all(target_os = "linux",
           any(target_arch = "mips",
               target_arch = "mipsel",
               target_arch = "powerpc")))]
-mod consts {
-    use libc;
-    pub const FIONBIO: libc::c_ulong = 0x667e;
-    pub const FIOCLEX: libc::c_ulong = 0x6601;
-    pub const FIONCLEX: libc::c_ulong = 0x6600;
-}
-pub use self::consts::*;
-
-#[cfg(any(target_os = "macos",
-          target_os = "ios",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "openbsd"))]
-pub const MSG_DONTWAIT: libc::c_int = 0x80;
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub const MSG_DONTWAIT: libc::c_int = 0x40;
+pub const FIOCLEX: libc::c_ulong = 0x6601;
 
 pub const WNOHANG: libc::c_int = 1;
 
@@ -122,14 +107,14 @@ pub struct passwd {
     pub pw_shell: *mut libc::c_char,
 }
 
+// This is really a function pointer (or a union of multiple function
+// pointers), except for constants like SIG_DFL.
+pub type sighandler_t = *mut libc::c_void;
+
+pub const SIG_DFL: sighandler_t = 0 as sighandler_t;
+pub const SIG_ERR: sighandler_t = !0 as sighandler_t;
+
 extern {
-    pub fn gettimeofday(timeval: *mut libc::timeval,
-                        tzp: *mut libc::c_void) -> libc::c_int;
-    pub fn select(nfds: libc::c_int,
-                  readfds: *mut fd_set,
-                  writefds: *mut fd_set,
-                  errorfds: *mut fd_set,
-                  timeout: *mut libc::timeval) -> libc::c_int;
     pub fn getsockopt(sockfd: libc::c_int,
                       level: libc::c_int,
                       optname: libc::c_int,
@@ -141,14 +126,21 @@ extern {
     pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int,
                    options: libc::c_int) -> libc::pid_t;
 
+    pub fn raise(signum: libc::c_int) -> libc::c_int;
+
     pub fn sigaction(signum: libc::c_int,
                      act: *const sigaction,
                      oldact: *mut sigaction) -> libc::c_int;
 
-    pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
-    pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
+    pub fn sigaltstack(ss: *const sigaltstack,
+                       oss: *mut sigaltstack) -> libc::c_int;
+
+    #[cfg(not(target_os = "android"))]
     pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
 
+    pub fn pthread_sigmask(how: libc::c_int, set: *const sigset_t,
+                           oldset: *mut sigset_t) -> libc::c_int;
+
     #[cfg(not(target_os = "ios"))]
     pub fn getpwuid_r(uid: libc::uid_t,
                       pwd: *mut passwd,
@@ -165,161 +157,188 @@ extern {
                     -> *mut libc::c_char;
 }
 
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-mod select {
-    pub const FD_SETSIZE: usize = 1024;
-
-    #[repr(C)]
-    pub struct fd_set {
-        fds_bits: [i32; (FD_SETSIZE / 32)]
-    }
-
-    pub fn fd_set(set: &mut fd_set, fd: i32) {
-        set.fds_bits[(fd / 32) as usize] |= 1 << ((fd % 32) as usize);
-    }
-}
-
-#[cfg(any(target_os = "android",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "openbsd",
-          target_os = "linux"))]
-mod select {
-    use usize;
-    use libc;
-
-    pub const FD_SETSIZE: usize = 1024;
-
-    #[repr(C)]
-    pub struct fd_set {
-        // FIXME: shouldn't this be a c_ulong?
-        fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS)]
-    }
-
-    pub fn fd_set(set: &mut fd_set, fd: i32) {
-        let fd = fd as usize;
-        set.fds_bits[fd / usize::BITS] |= 1 << (fd % usize::BITS);
-    }
+// Ugh. This is only available as an inline until Android API 21.
+#[cfg(target_os = "android")]
+pub unsafe fn sigemptyset(set: *mut sigset_t) -> libc::c_int {
+    use intrinsics;
+    intrinsics::write_bytes(set, 0, 1);
+    return 0;
 }
 
-#[cfg(any(all(target_os = "linux",
-              any(target_arch = "x86",
-                  target_arch = "x86_64",
-                  target_arch = "arm",
-                  target_arch = "aarch64")),
+#[cfg(any(target_os = "linux",
           target_os = "android"))]
-mod signal {
+mod signal_os {
+    pub use self::arch::{SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_SETMASK,
+                         sigaction, sigaltstack};
     use libc;
 
-    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
-    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002;
-    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
-    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
-    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
-    pub const SA_RESTART: libc::c_ulong = 0x10000000;
-    pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
-    pub const SIGCHLD: libc::c_int = 17;
-
-    // This definition is not as accurate as it could be, {pid, uid, status} is
-    // actually a giant union. Currently we're only interested in these fields,
-    // however.
+    #[cfg(any(target_arch = "x86",
+              target_arch = "x86_64",
+              target_arch = "arm",
+              target_arch = "mips",
+              target_arch = "mipsel"))]
+    pub const SIGSTKSZ: libc::size_t = 8192;
+
+    // This is smaller on musl and Android, but no harm in being generous.
+    #[cfg(any(target_arch = "aarch64",
+              target_arch = "powerpc"))]
+    pub const SIGSTKSZ: libc::size_t = 16384;
+
+    // This definition is intentionally a subset of the C structure: the
+    // fields after si_code are actually a giant union. We're only
+    // interested in si_addr for this module, though.
     #[repr(C)]
     pub struct siginfo {
-        si_signo: libc::c_int,
-        si_errno: libc::c_int,
-        si_code: libc::c_int,
-        pub pid: libc::pid_t,
-        pub uid: libc::uid_t,
-        pub status: libc::c_int,
+        _signo: libc::c_int,
+        _errno: libc::c_int,
+        _code: libc::c_int,
+        // This structure will need extra padding here for MIPS64.
+        pub si_addr: *mut libc::c_void
     }
 
+    #[cfg(all(target_os = "linux", target_pointer_width = "32"))]
     #[repr(C)]
-    pub struct sigaction {
-        pub sa_handler: extern fn(libc::c_int),
-        pub sa_mask: sigset_t,
-        pub sa_flags: libc::c_ulong,
-        sa_restorer: *mut libc::c_void,
-    }
-
-    unsafe impl ::marker::Send for sigaction { }
-    unsafe impl ::marker::Sync for sigaction { }
-
-    #[repr(C)]
-    #[cfg(target_pointer_width = "32")]
     pub struct sigset_t {
         __val: [libc::c_ulong; 32],
     }
 
+    #[cfg(all(target_os = "linux", target_pointer_width = "64"))]
     #[repr(C)]
-    #[cfg(target_pointer_width = "64")]
     pub struct sigset_t {
         __val: [libc::c_ulong; 16],
     }
-}
 
-#[cfg(all(target_os = "linux",
-          any(target_arch = "mips",
-              target_arch = "mipsel",
-              target_arch = "powerpc")))]
-mod signal {
-    use libc;
-
-    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
-    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000;
-    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
-    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
-    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
-    pub const SA_RESTART: libc::c_ulong = 0x10000000;
-    pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
-    pub const SIGCHLD: libc::c_int = 18;
-
-    // This definition is not as accurate as it could be, {pid, uid, status} is
-    // actually a giant union. Currently we're only interested in these fields,
-    // however.
-    #[repr(C)]
-    pub struct siginfo {
-        si_signo: libc::c_int,
-        si_code: libc::c_int,
-        si_errno: libc::c_int,
-        pub pid: libc::pid_t,
-        pub uid: libc::uid_t,
-        pub status: libc::c_int,
+    // Android for MIPS has a 128-bit sigset_t, but we don't currently
+    // support it. Android for AArch64 technically has a structure of a
+    // single ulong.
+    #[cfg(target_os = "android")]
+    pub type sigset_t = libc::c_ulong;
+
+    #[cfg(any(target_arch = "x86",
+              target_arch = "x86_64",
+              target_arch = "powerpc",
+              target_arch = "arm",
+              target_arch = "aarch64"))]
+    mod arch {
+        use libc;
+        use super::super::sighandler_t;
+        use super::sigset_t;
+
+        pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
+        pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
+
+        pub const SIGBUS: libc::c_int = 7;
+
+        pub const SIG_SETMASK: libc::c_int = 2;
+
+        #[cfg(target_os = "linux")]
+        #[repr(C)]
+        pub struct sigaction {
+            pub sa_sigaction: sighandler_t,
+            pub sa_mask: sigset_t,
+            pub sa_flags: libc::c_ulong,
+            _restorer: *mut libc::c_void,
+        }
+
+        #[cfg(all(target_os = "android", target_pointer_width = "32"))]
+        #[repr(C)]
+        pub struct sigaction {
+            pub sa_sigaction: sighandler_t,
+            pub sa_flags: libc::c_ulong,
+            _restorer: *mut libc::c_void,
+            pub sa_mask: sigset_t,
+        }
+
+        #[cfg(all(target_os = "android", target_pointer_width = "64"))]
+        #[repr(C)]
+        pub struct sigaction {
+            pub sa_flags: libc::c_uint,
+            pub sa_sigaction: sighandler_t,
+            pub sa_mask: sigset_t,
+            _restorer: *mut libc::c_void,
+        }
+
+        #[repr(C)]
+        pub struct sigaltstack {
+            pub ss_sp: *mut libc::c_void,
+            pub ss_flags: libc::c_int,
+            pub ss_size: libc::size_t
+        }
     }
 
-    #[repr(C)]
-    pub struct sigaction {
-        pub sa_flags: libc::c_uint,
-        pub sa_handler: extern fn(libc::c_int),
-        pub sa_mask: sigset_t,
-        sa_restorer: *mut libc::c_void,
-        sa_resv: [libc::c_int; 1],
-    }
-
-    unsafe impl ::marker::Send for sigaction { }
-    unsafe impl ::marker::Sync for sigaction { }
-
-    #[repr(C)]
-    pub struct sigset_t {
-        __val: [libc::c_ulong; 32],
+    #[cfg(any(target_arch = "mips",
+              target_arch = "mipsel"))]
+    mod arch {
+        use libc;
+        use super::super::sighandler_t;
+        use super::sigset_t;
+
+        pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
+        pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
+
+        pub const SIGBUS: libc::c_int = 10;
+
+        pub const SIG_SETMASK: libc::c_int = 3;
+
+        #[cfg(all(target_os = "linux", not(target_env = "musl")))]
+        #[repr(C)]
+        pub struct sigaction {
+            pub sa_flags: libc::c_uint,
+            pub sa_sigaction: sighandler_t,
+            pub sa_mask: sigset_t,
+            _restorer: *mut libc::c_void,
+            _resv: [libc::c_int; 1],
+        }
+
+        #[cfg(target_env = "musl")]
+        #[repr(C)]
+        pub struct sigaction {
+            pub sa_sigaction: sighandler_t,
+            pub sa_mask: sigset_t,
+            pub sa_flags: libc::c_ulong,
+            _restorer: *mut libc::c_void,
+        }
+
+        #[cfg(target_os = "android")]
+        #[repr(C)]
+        pub struct sigaction {
+            pub sa_flags: libc::c_uint,
+            pub sa_sigaction: sighandler_t,
+            pub sa_mask: sigset_t,
+        }
+
+        #[repr(C)]
+        pub struct sigaltstack {
+            pub ss_sp: *mut libc::c_void,
+            pub ss_size: libc::size_t,
+            pub ss_flags: libc::c_int,
+        }
     }
 }
 
 #[cfg(any(target_os = "macos",
           target_os = "ios",
           target_os = "freebsd",
-          target_os = "dragonfly"))]
-mod signal {
+          target_os = "dragonfly",
+          target_os = "bitrig",
+          target_os = "openbsd"))]
+mod signal_os {
     use libc;
+    use super::sighandler_t;
 
     pub const SA_ONSTACK: libc::c_int = 0x0001;
-    pub const SA_RESTART: libc::c_int = 0x0002;
-    pub const SA_RESETHAND: libc::c_int = 0x0004;
-    pub const SA_NOCLDSTOP: libc::c_int = 0x0008;
-    pub const SA_NODEFER: libc::c_int = 0x0010;
-    pub const SA_NOCLDWAIT: libc::c_int = 0x0020;
     pub const SA_SIGINFO: libc::c_int = 0x0040;
-    pub const SIGCHLD: libc::c_int = 20;
+
+    pub const SIGBUS: libc::c_int = 10;
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub const SIGSTKSZ: libc::size_t = 131072;
+    // FreeBSD's is actually arch-dependent, but never more than 40960.
+    // No harm in being generous.
+    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+    pub const SIGSTKSZ: libc::size_t = 40960;
+
+    pub const SIG_SETMASK: libc::c_int = 3;
 
     #[cfg(any(target_os = "macos",
               target_os = "ios"))]
@@ -329,61 +348,53 @@ mod signal {
     pub struct sigset_t {
         bits: [u32; 4],
     }
+    #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+    pub type sigset_t = libc::c_uint;
 
     // This structure has more fields, but we're not all that interested in
     // them.
+    #[cfg(any(target_os = "macos", target_os = "ios",
+              target_os = "freebsd", target_os = "dragonfly"))]
+    #[repr(C)]
+    pub struct siginfo {
+        pub _signo: libc::c_int,
+        pub _errno: libc::c_int,
+        pub _code: libc::c_int,
+        pub _pid: libc::pid_t,
+        pub _uid: libc::uid_t,
+        pub _status: libc::c_int,
+        pub si_addr: *mut libc::c_void
+    }
+    #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
     #[repr(C)]
     pub struct siginfo {
         pub si_signo: libc::c_int,
-        pub si_errno: libc::c_int,
         pub si_code: libc::c_int,
-        pub pid: libc::pid_t,
-        pub uid: libc::uid_t,
-        pub status: libc::c_int,
+        pub si_errno: libc::c_int,
+        pub si_addr: *mut libc::c_void
     }
 
+    #[cfg(any(target_os = "macos", target_os = "ios",
+              target_os = "bitrig", target_os = "openbsd"))]
     #[repr(C)]
     pub struct sigaction {
-        pub sa_handler: extern fn(libc::c_int),
-        pub sa_flags: libc::c_int,
+        pub sa_sigaction: sighandler_t,
         pub sa_mask: sigset_t,
+        pub sa_flags: libc::c_int,
     }
-}
-
-#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
-mod signal {
-    use libc;
-
-    pub const SA_ONSTACK: libc::c_int = 0x0001;
-    pub const SA_RESTART: libc::c_int = 0x0002;
-    pub const SA_RESETHAND: libc::c_int = 0x0004;
-    pub const SA_NOCLDSTOP: libc::c_int = 0x0008;
-    pub const SA_NODEFER: libc::c_int = 0x0010;
-    pub const SA_NOCLDWAIT: libc::c_int = 0x0020;
-    pub const SA_SIGINFO: libc::c_int = 0x0040;
-    pub const SIGCHLD: libc::c_int = 20;
-
-    pub type sigset_t = libc::c_uint;
 
-    // This structure has more fields, but we're not all that interested in
-    // them.
+    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
     #[repr(C)]
-    pub struct siginfo {
-        pub si_signo: libc::c_int,
-        pub si_code: libc::c_int,
-        pub si_errno: libc::c_int,
-        // FIXME: Bitrig has a crazy union here in the siginfo, I think this
-        // layout will still work tho.  The status might be off by the size of
-        // a clock_t by my reading, but we can fix this later.
-        pub pid: libc::pid_t,
-        pub uid: libc::uid_t,
-        pub status: libc::c_int,
+    pub struct sigaction {
+        pub sa_sigaction: sighandler_t,
+        pub sa_flags: libc::c_int,
+        pub sa_mask: sigset_t,
     }
 
     #[repr(C)]
-    pub struct sigaction {
-        pub sa_handler: extern fn(libc::c_int),
-        pub sa_mask: sigset_t,
-        pub sa_flags: libc::c_int,
+    pub struct sigaltstack {
+        pub ss_sp: *mut libc::c_void,
+        pub ss_size: libc::size_t,
+        pub ss_flags: libc::c_int,
     }
 }
diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs
index acf6fbc24e4..695d0ddfaaf 100644
--- a/src/libstd/sys/unix/process.rs
+++ b/src/libstd/sys/unix/process.rs
@@ -17,6 +17,7 @@ use ffi::{OsString, OsStr, CString, CStr};
 use fmt;
 use io::{self, Error, ErrorKind};
 use libc::{self, pid_t, c_void, c_int, gid_t, uid_t};
+use mem;
 use ptr;
 use sys::fd::FileDesc;
 use sys::fs::{File, OpenOptions};
@@ -313,6 +314,23 @@ impl Process {
         if !envp.is_null() {
             *sys::os::environ() = envp as *const _;
         }
+
+        // Reset signal handling so the child process starts in a
+        // standardized state. libstd ignores SIGPIPE, and signal-handling
+        // libraries often set a mask. Child processes inherit ignored
+        // signals and the signal mask from their parent, but most
+        // UNIX programs do not reset these things on their own, so we
+        // need to clean things up now to avoid confusing the program
+        // we're about to run.
+        let mut set: c::sigset_t = mem::uninitialized();
+        if c::sigemptyset(&mut set) != 0 ||
+           c::pthread_sigmask(c::SIG_SETMASK, &set, ptr::null_mut()) != 0 ||
+           libc::funcs::posix01::signal::signal(
+               libc::SIGPIPE, mem::transmute(c::SIG_DFL)
+           ) == mem::transmute(c::SIG_ERR) {
+            fail(&mut output);
+        }
+
         let _ = libc::execvp(*argv, argv);
         fail(&mut output)
     }
@@ -418,3 +436,69 @@ fn translate_status(status: c_int) -> ExitStatus {
         ExitStatus::Signal(imp::WTERMSIG(status))
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use prelude::v1::*;
+
+    use ffi::OsStr;
+    use mem;
+    use ptr;
+    use libc;
+    use slice;
+    use sys::{self, c, cvt, pipe};
+
+    #[cfg(not(target_os = "android"))]
+    extern {
+        fn sigaddset(set: *mut c::sigset_t, signum: libc::c_int) -> libc::c_int;
+    }
+
+    #[cfg(target_os = "android")]
+    unsafe fn sigaddset(set: *mut c::sigset_t, signum: libc::c_int) -> libc::c_int {
+        let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<c::sigset_t>());
+        let bit = (signum - 1) as usize;
+        raw[bit / 8] |= 1 << (bit % 8);
+        return 0;
+    }
+
+    #[test]
+    fn test_process_mask() {
+        unsafe {
+            // Test to make sure that a signal mask does not get inherited.
+            let cmd = Command::new(OsStr::new("cat"));
+            let (stdin_read, stdin_write) = sys::pipe::anon_pipe().unwrap();
+            let (stdout_read, stdout_write) = sys::pipe::anon_pipe().unwrap();
+
+            let mut set: c::sigset_t = mem::uninitialized();
+            let mut old_set: c::sigset_t = mem::uninitialized();
+            cvt(c::sigemptyset(&mut set)).unwrap();
+            cvt(sigaddset(&mut set, libc::SIGINT)).unwrap();
+            cvt(c::pthread_sigmask(c::SIG_SETMASK, &set, &mut old_set)).unwrap();
+
+            let cat = Process::spawn(&cmd, Stdio::Raw(stdin_read.raw()),
+                                           Stdio::Raw(stdout_write.raw()),
+                                           Stdio::None).unwrap();
+            drop(stdin_read);
+            drop(stdout_write);
+
+            cvt(c::pthread_sigmask(c::SIG_SETMASK, &old_set, ptr::null_mut())).unwrap();
+
+            cvt(libc::funcs::posix88::signal::kill(cat.id() as libc::pid_t, libc::SIGINT)).unwrap();
+            // We need to wait until SIGINT is definitely delivered. The
+            // easiest way is to write something to cat, and try to read it
+            // back: if SIGINT is unmasked, it'll get delivered when cat is
+            // next scheduled.
+            let _ = stdin_write.write(b"Hello");
+            drop(stdin_write);
+
+            // Either EOF or failure (EPIPE) is okay.
+            let mut buf = [0; 5];
+            if let Ok(ret) = stdout_read.read(&mut buf) {
+                assert!(ret == 0);
+            }
+
+            cat.wait().unwrap();
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index 2bc280d1274..52494a17b9d 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -44,11 +44,12 @@ mod imp {
     use mem;
     use ptr;
     use intrinsics;
-    use self::signal::{siginfo, sigaction, SIGBUS, SIG_DFL,
-                       SA_SIGINFO, SA_ONSTACK, sigaltstack,
-                       SIGSTKSZ};
+    use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
+                 SA_SIGINFO, SA_ONSTACK, sigaltstack,
+                 SIGSTKSZ, sighandler_t, raise};
     use libc;
     use libc::funcs::posix88::mman::{mmap, munmap};
+    use libc::funcs::posix01::signal::signal;
     use libc::consts::os::posix88::{SIGSEGV,
                                     PROT_READ,
                                     PROT_WRITE,
@@ -120,7 +121,7 @@ mod imp {
 
     pub unsafe fn make_handler() -> Handler {
         let alt_stack = mmap(ptr::null_mut(),
-                             signal::SIGSTKSZ,
+                             SIGSTKSZ,
                              PROT_READ | PROT_WRITE,
                              MAP_PRIVATE | MAP_ANON,
                              -1,
@@ -143,138 +144,6 @@ mod imp {
     pub unsafe fn drop_handler(handler: &mut Handler) {
         munmap(handler._data, SIGSTKSZ);
     }
-
-    pub type sighandler_t = *mut libc::c_void;
-
-    #[cfg(any(all(target_os = "linux", target_arch = "x86"), // may not match
-              all(target_os = "linux", target_arch = "x86_64"),
-              all(target_os = "linux", target_arch = "arm"), // may not match
-              all(target_os = "linux", target_arch = "aarch64"),
-              all(target_os = "linux", target_arch = "mips"), // may not match
-              all(target_os = "linux", target_arch = "mipsel"), // may not match
-              all(target_os = "linux", target_arch = "powerpc"), // may not match
-              target_os = "android"))] // may not match
-    mod signal {
-        use libc;
-        pub use super::sighandler_t;
-
-        pub static SA_ONSTACK: libc::c_int = 0x08000000;
-        pub static SA_SIGINFO: libc::c_int = 0x00000004;
-        pub static SIGBUS: libc::c_int = 7;
-
-        pub static SIGSTKSZ: libc::size_t = 8192;
-
-        pub const SIG_DFL: sighandler_t = 0 as sighandler_t;
-
-        // This definition is not as accurate as it could be, {si_addr} is
-        // actually a giant union. Currently we're only interested in that field,
-        // however.
-        #[repr(C)]
-        pub struct siginfo {
-            si_signo: libc::c_int,
-            si_errno: libc::c_int,
-            si_code: libc::c_int,
-            pub si_addr: *mut libc::c_void
-        }
-
-        #[repr(C)]
-        pub struct sigaction {
-            pub sa_sigaction: sighandler_t,
-            pub sa_mask: sigset_t,
-            pub sa_flags: libc::c_int,
-            sa_restorer: *mut libc::c_void,
-        }
-
-        #[cfg(target_pointer_width = "32")]
-        #[repr(C)]
-        pub struct sigset_t {
-            __val: [libc::c_ulong; 32],
-        }
-        #[cfg(target_pointer_width = "64")]
-        #[repr(C)]
-        pub struct sigset_t {
-            __val: [libc::c_ulong; 16],
-        }
-
-        #[repr(C)]
-        pub struct sigaltstack {
-            pub ss_sp: *mut libc::c_void,
-            pub ss_flags: libc::c_int,
-            pub ss_size: libc::size_t
-        }
-
-    }
-
-    #[cfg(any(target_os = "macos",
-              target_os = "bitrig",
-              target_os = "openbsd"))]
-    mod signal {
-        use libc;
-        pub use super::sighandler_t;
-
-        pub const SA_ONSTACK: libc::c_int = 0x0001;
-        pub const SA_SIGINFO: libc::c_int = 0x0040;
-        pub const SIGBUS: libc::c_int = 10;
-
-        #[cfg(target_os = "macos")]
-        pub const SIGSTKSZ: libc::size_t = 131072;
-        #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
-        pub const SIGSTKSZ: libc::size_t = 40960;
-
-        pub const SIG_DFL: sighandler_t = 0 as sighandler_t;
-
-        pub type sigset_t = u32;
-
-        // This structure has more fields, but we're not all that interested in
-        // them.
-        #[cfg(target_os = "macos")]
-        #[repr(C)]
-        pub struct siginfo {
-            pub si_signo: libc::c_int,
-            pub si_errno: libc::c_int,
-            pub si_code: libc::c_int,
-            pub pid: libc::pid_t,
-            pub uid: libc::uid_t,
-            pub status: libc::c_int,
-            pub si_addr: *mut libc::c_void
-        }
-
-        #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
-        #[repr(C)]
-        pub struct siginfo {
-            pub si_signo: libc::c_int,
-            pub si_code: libc::c_int,
-            pub si_errno: libc::c_int,
-            //union
-            pub si_addr: *mut libc::c_void
-        }
-
-        #[repr(C)]
-        pub struct sigaltstack {
-            pub ss_sp: *mut libc::c_void,
-            pub ss_size: libc::size_t,
-            pub ss_flags: libc::c_int
-        }
-
-        #[repr(C)]
-        pub struct sigaction {
-            pub sa_sigaction: sighandler_t,
-            pub sa_mask: sigset_t,
-            pub sa_flags: libc::c_int,
-        }
-    }
-
-    extern {
-        pub fn signal(signum: libc::c_int, handler: sighandler_t) -> sighandler_t;
-        pub fn raise(signum: libc::c_int) -> libc::c_int;
-
-        pub fn sigaction(signum: libc::c_int,
-                         act: *const sigaction,
-                         oldact: *mut sigaction) -> libc::c_int;
-
-        pub fn sigaltstack(ss: *const sigaltstack,
-                           oss: *mut sigaltstack) -> libc::c_int;
-    }
 }
 
 #[cfg(not(any(target_os = "linux",
diff --git a/src/test/run-pass/process-sigpipe.rs b/src/test/run-pass/process-sigpipe.rs
new file mode 100644
index 00000000000..5bff4fa080a
--- /dev/null
+++ b/src/test/run-pass/process-sigpipe.rs
@@ -0,0 +1,39 @@
+// Copyright 2015 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.
+
+// ignore-android since the dynamic linker sets a SIGPIPE handler (to do
+// a crash report) so inheritance is moot on the entire platform
+
+// libstd ignores SIGPIPE, and other libraries may set signal masks.
+// Make sure that these behaviors don't get inherited to children
+// spawned via std::process, since they're needed for traditional UNIX
+// filter behavior. This test checks that `yes | head` terminates
+// (instead of running forever), and that it does not print an error
+// message about a broken pipe.
+
+use std::process;
+use std::thread;
+
+#[cfg(unix)]
+fn main() {
+    // Just in case `yes` doesn't check for EPIPE...
+    thread::spawn(|| {
+        thread::sleep_ms(5000);
+        process::exit(1);
+    });
+    let output = process::Command::new("sh").arg("-c").arg("yes | head").output().unwrap();
+    assert!(output.status.success());
+    assert!(output.stderr.len() == 0);
+}
+
+#[cfg(not(unix))]
+fn main() {
+    // Not worried about signal masks on other platforms
+}