Skip to content

Commit 1f81ef4

Browse files
committed
Atomically set CLOEXEC on duplicated sockets
For Bitrig, NetBSD and OpenBSD the constant was incorrectly in posix01, when it's actually posix08, so we move it. This is a [breaking-change], but we already had one in #27930. Fix NetBSD's F_DUPFD_CLOEXEC constant. For a similar feature detection, see this musl thread: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 This assumes that an int literal has type `c_int` for varidic functions.
1 parent 4bb9023 commit 1f81ef4

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

src/liblibc/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -3614,6 +3614,7 @@ pub mod consts {
36143614
pub mod posix08 {
36153615
use types::os::arch::c95::c_int;
36163616
pub const O_CLOEXEC: c_int = 0x80000;
3617+
pub const F_DUPFD_CLOEXEC: c_int = 1030;
36173618
}
36183619
#[cfg(any(target_arch = "arm",
36193620
target_arch = "aarch64",
@@ -4285,11 +4286,13 @@ pub mod consts {
42854286
pub mod posix08 {
42864287
use types::os::arch::c95::c_int;
42874288
pub const O_CLOEXEC: c_int = 0x100000;
4289+
pub const F_DUPFD_CLOEXEC: c_int = 17;
42884290
}
42894291
#[cfg(target_os = "dragonfly")]
42904292
pub mod posix08 {
42914293
use types::os::arch::c95::c_int;
42924294
pub const O_CLOEXEC: c_int = 0x20000;
4295+
pub const F_DUPFD_CLOEXEC: c_int = 17;
42934296
}
42944297
pub mod bsd44 {
42954298
use types::os::arch::c95::c_int;
@@ -4657,7 +4660,6 @@ pub mod consts {
46574660
pub const F_GETLK : c_int = 7;
46584661
pub const F_SETLK : c_int = 8;
46594662
pub const F_SETLKW : c_int = 9;
4660-
pub const F_DUPFD_CLOEXEC : c_int = 10;
46614663

46624664
pub const SIGTRAP : c_int = 5;
46634665
pub const SIG_IGN: size_t = 1;
@@ -4739,11 +4741,13 @@ pub mod consts {
47394741
pub mod posix08 {
47404742
use types::os::arch::c95::c_int;
47414743
pub const O_CLOEXEC: c_int = 0x10000;
4744+
pub const F_DUPFD_CLOEXEC: c_int = 10;
47424745
}
47434746
#[cfg(target_os = "netbsd")]
47444747
pub mod posix08 {
47454748
use types::os::arch::c95::c_int;
47464749
pub const O_CLOEXEC: c_int = 0x400000;
4750+
pub const F_DUPFD_CLOEXEC: c_int = 12;
47474751
}
47484752
pub mod bsd44 {
47494753
use types::os::arch::c95::c_int;
@@ -5186,6 +5190,7 @@ pub mod consts {
51865190
pub mod posix08 {
51875191
use types::os::arch::c95::c_int;
51885192
pub const O_CLOEXEC: c_int = 0x1000000;
5193+
pub const F_DUPFD_CLOEXEC: c_int = 67;
51895194
}
51905195
pub mod bsd44 {
51915196
use types::os::arch::c95::c_int;

src/libstd/sys/unix/net.rs

+25-5
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ use prelude::v1::*;
1313
use ffi::CStr;
1414
use io;
1515
use libc::{self, c_int, size_t};
16+
use net::SocketAddr;
1617
use str;
18+
use sync::atomic::{self, AtomicBool};
1719
use sys::c;
18-
use net::SocketAddr;
1920
use sys::fd::FileDesc;
2021
use sys_common::{AsInner, FromInner, IntoInner};
2122
use sys_common::net::{getsockopt, setsockopt};
@@ -66,10 +67,29 @@ impl Socket {
6667
}
6768

6869
pub fn duplicate(&self) -> io::Result<Socket> {
69-
let fd = try!(cvt(unsafe { libc::dup(self.0.raw()) }));
70-
let fd = FileDesc::new(fd);
71-
fd.set_cloexec();
72-
Ok(Socket(fd))
70+
use libc::funcs::posix88::fcntl::fcntl;
71+
let make_socket = |fd| {
72+
let fd = FileDesc::new(fd);
73+
fd.set_cloexec();
74+
Socket(fd)
75+
};
76+
static EMULATE_F_DUPFD_CLOEXEC: AtomicBool = AtomicBool::new(false);
77+
if !EMULATE_F_DUPFD_CLOEXEC.load(atomic::Ordering::Relaxed) {
78+
match cvt(unsafe { fcntl(self.0.raw(), libc::F_DUPFD_CLOEXEC, 0) }) {
79+
// `EINVAL` can only be returned on two occasions: Invalid
80+
// command (second parameter) or invalid third parameter. 0 is
81+
// always a valid third parameter, so it must be the second
82+
// parameter.
83+
//
84+
// Store the result in a global variable so we don't try each
85+
// syscall twice.
86+
Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
87+
EMULATE_F_DUPFD_CLOEXEC.store(true, atomic::Ordering::Relaxed);
88+
}
89+
res => return res.map(make_socket),
90+
}
91+
}
92+
cvt(unsafe { fcntl(self.0.raw(), libc::F_DUPFD, 0) }).map(make_socket)
7393
}
7494

7595
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {

0 commit comments

Comments
 (0)