about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libstd/sys/unix/c.rs42
-rw-r--r--src/libstd/sys/unix/fd.rs15
-rw-r--r--src/libstd/sys/unix/fs2.rs4
-rw-r--r--src/libstd/sys/unix/net.rs15
-rw-r--r--src/libstd/sys/unix/pipe2.rs4
-rw-r--r--src/test/run-pass/fds-are-cloexec.rs75
6 files changed, 125 insertions, 30 deletions
diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs
index 5ae508e4610..282e5668e6e 100644
--- a/src/libstd/sys/unix/c.rs
+++ b/src/libstd/sys/unix/c.rs
@@ -26,39 +26,35 @@ use libc;
           target_os = "dragonfly",
           target_os = "bitrig",
           target_os = "openbsd"))]
-pub const FIONBIO: libc::c_ulong = 0x8004667e;
-#[cfg(any(all(target_os = "linux",
-              any(target_arch = "x86",
-                  target_arch = "x86_64",
-                  target_arch = "arm",
-                  target_arch = "aarch64")),
-          target_os = "android"))]
-pub const FIONBIO: libc::c_ulong = 0x5421;
-#[cfg(all(target_os = "linux",
-          any(target_arch = "mips",
-              target_arch = "mipsel",
-              target_arch = "powerpc")))]
-pub const FIONBIO: libc::c_ulong = 0x667e;
-
-#[cfg(any(target_os = "macos",
-          target_os = "ios",
-          target_os = "freebsd",
-          target_os = "dragonfly",
-          target_os = "bitrig",
-          target_os = "openbsd"))]
-pub const FIOCLEX: libc::c_ulong = 0x20006601;
+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;
+}
 #[cfg(any(all(target_os = "linux",
               any(target_arch = "x86",
                   target_arch = "x86_64",
                   target_arch = "arm",
                   target_arch = "aarch64")),
           target_os = "android"))]
-pub const FIOCLEX: libc::c_ulong = 0x5451;
+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;
+}
 #[cfg(all(target_os = "linux",
           any(target_arch = "mips",
               target_arch = "mipsel",
               target_arch = "powerpc")))]
-pub const FIOCLEX: libc::c_ulong = 0x6601;
+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",
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index f7c57c3f5e5..4ef09b91c25 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -13,6 +13,7 @@ use core::prelude::*;
 use io;
 use libc::{self, c_int, size_t, c_void};
 use mem;
+use sys::c;
 use sys::cvt;
 use sys_common::AsInner;
 
@@ -51,6 +52,20 @@ impl FileDesc {
         }));
         Ok(ret as usize)
     }
+
+    pub fn set_cloexec(&self) {
+        unsafe {
+            let ret = c::ioctl(self.fd, c::FIOCLEX);
+            debug_assert_eq!(ret, 0);
+        }
+    }
+
+    pub fn unset_cloexec(&self) {
+        unsafe {
+            let ret = c::ioctl(self.fd, c::FIONCLEX);
+            debug_assert_eq!(ret, 0);
+        }
+    }
 }
 
 impl AsInner<c_int> for FileDesc {
diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs
index c0426af051b..20b1aac8f45 100644
--- a/src/libstd/sys/unix/fs2.rs
+++ b/src/libstd/sys/unix/fs2.rs
@@ -215,7 +215,9 @@ impl File {
         let fd = try!(cvt_r(|| unsafe {
             libc::open(path.as_ptr(), flags, opts.mode)
         }));
-        Ok(File(FileDesc::new(fd)))
+        let fd = FileDesc::new(fd);
+        fd.set_cloexec();
+        Ok(File(fd))
     }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index 908136a42ab..2e1cbb2a1e1 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -47,7 +47,9 @@ impl Socket {
         };
         unsafe {
             let fd = try!(cvt(libc::socket(fam, ty, 0)));
-            Ok(Socket(FileDesc::new(fd)))
+            let fd = FileDesc::new(fd);
+            fd.set_cloexec();
+            Ok(Socket(fd))
         }
     }
 
@@ -56,13 +58,16 @@ impl Socket {
         let fd = try!(cvt_r(|| unsafe {
             libc::accept(self.0.raw(), storage, len)
         }));
-        Ok(Socket(FileDesc::new(fd)))
+        let fd = FileDesc::new(fd);
+        fd.set_cloexec();
+        Ok(Socket(fd))
     }
 
     pub fn duplicate(&self) -> io::Result<Socket> {
-        cvt(unsafe { libc::dup(self.0.raw()) }).map(|fd| {
-            Socket(FileDesc::new(fd))
-        })
+        let fd = try!(cvt(unsafe { libc::dup(self.0.raw()) }));
+        let fd = FileDesc::new(fd);
+        fd.set_cloexec();
+        Ok(Socket(fd))
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
diff --git a/src/libstd/sys/unix/pipe2.rs b/src/libstd/sys/unix/pipe2.rs
index 7af2c0f0b2a..2fd4d6dd311 100644
--- a/src/libstd/sys/unix/pipe2.rs
+++ b/src/libstd/sys/unix/pipe2.rs
@@ -32,7 +32,9 @@ pub unsafe fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
 
 impl AnonPipe {
     pub fn from_fd(fd: libc::c_int) -> AnonPipe {
-        AnonPipe(FileDesc::new(fd))
+        let fd = FileDesc::new(fd);
+        fd.set_cloexec();
+        AnonPipe(fd)
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs
new file mode 100644
index 00000000000..ec59b4dc03d
--- /dev/null
+++ b/src/test/run-pass/fds-are-cloexec.rs
@@ -0,0 +1,75 @@
+// 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-windows
+
+#![feature(libc)]
+
+extern crate libc;
+
+use std::env;
+use std::fs::{self, File};
+use std::io;
+use std::net::{TcpListener, TcpStream, UdpSocket};
+use std::os::unix::prelude::*;
+use std::process::Command;
+use std::thread;
+
+fn main() {
+    let args = env::args().collect::<Vec<_>>();
+    if args.len() == 1 {
+        parent()
+    } else {
+        child(&args)
+    }
+}
+
+fn parent() {
+    let file = File::open("Makefile").unwrap();
+    let _dir = fs::read_dir("/").unwrap();
+    let tcp1 = TcpListener::bind("127.0.0.1:0").unwrap();
+    assert_eq!(tcp1.as_raw_fd(), file.as_raw_fd() + 2);
+    let tcp2 = tcp1.try_clone().unwrap();
+    let addr = tcp1.local_addr().unwrap();
+    let t = thread::scoped(|| TcpStream::connect(addr).unwrap());
+    let tcp3 = tcp1.accept().unwrap().0;
+    let tcp4 = t.join();
+    let tcp5 = tcp3.try_clone().unwrap();
+    let tcp6 = tcp4.try_clone().unwrap();
+    let udp1 = UdpSocket::bind("127.0.0.1:0").unwrap();
+    let udp2 = udp1.try_clone().unwrap();
+
+    let status = Command::new(env::args().next().unwrap())
+                        .arg(file.as_raw_fd().to_string())
+                        .arg((file.as_raw_fd() + 1).to_string())
+                        .arg(tcp1.as_raw_fd().to_string())
+                        .arg(tcp2.as_raw_fd().to_string())
+                        .arg(tcp3.as_raw_fd().to_string())
+                        .arg(tcp4.as_raw_fd().to_string())
+                        .arg(tcp5.as_raw_fd().to_string())
+                        .arg(tcp6.as_raw_fd().to_string())
+                        .arg(udp1.as_raw_fd().to_string())
+                        .arg(udp2.as_raw_fd().to_string())
+                        .status()
+                        .unwrap();
+    assert!(status.success());
+}
+
+fn child(args: &[String]) {
+    let mut b = [0u8; 2];
+    for arg in &args[1..] {
+        let fd: libc::c_int = arg.parse().unwrap();
+        unsafe {
+            assert_eq!(libc::read(fd, b.as_mut_ptr() as *mut _, 2), -1);
+            assert_eq!(io::Error::last_os_error().raw_os_error(),
+                       Some(libc::EBADF));
+        }
+    }
+}