diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index e5242c5bf861a..e27e4ba5af2cf 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 d70b9f099037a..a8127b3200f36 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -769,24 +769,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 1e68eac5a6735..99a6731c57d95 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 acf6fbc24e461..695d0ddfaaf61 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::()); + 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 2bc280d127439..52494a17b9d24 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 0000000000000..5bff4fa080a34 --- /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 or the MIT license +// , 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 +}