From cc53f4e9f48747d44718bb1b51e549437edae916 Mon Sep 17 00:00:00 2001 From: Adrian Budau Date: Wed, 19 Dec 2018 16:13:43 +0200 Subject: [PATCH 1/3] Fix pipe2 and accept4 on static linked executables on linux (like musl). --- src/libstd/lib.rs | 1 + src/libstd/sys/unix/net.rs | 25 ++++++++++-------- src/libstd/sys/unix/pipe.rs | 30 ++++++++++----------- src/libstd/sys/unix/weak.rs | 52 +++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ead38f2112687..9042cb3c72d60 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -250,6 +250,7 @@ #![feature(cfg_target_vendor)] #![feature(char_error_internals)] #![feature(compiler_builtins_lib)] +#![feature(concat_idents)] #![feature(const_int_ops)] #![feature(const_ip)] #![feature(const_raw_ptr_deref)] diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index d922be520d4be..f30817e69ab0e 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -203,18 +203,21 @@ impl Socket { // Linux. This was added in 2.6.28, however, and because we support // 2.6.18 we must detect this support dynamically. if cfg!(target_os = "linux") { - weak! { - fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int + syscall! { + fn accept4( + fd: c_int, + addr: *mut sockaddr, + addr_len: *mut socklen_t, + flags: c_int + ) -> c_int } - if let Some(accept) = accept4.get() { - let res = cvt_r(|| unsafe { - accept(self.0.raw(), storage, len, SOCK_CLOEXEC) - }); - match res { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), - } + let res = cvt_r(|| unsafe { + accept4(self.0.raw(), storage, len, SOCK_CLOEXEC) + }); + match res { + Ok(fd) => return Ok(Socket(FileDesc::new(fd))), + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} + Err(e) => return Err(e), } } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 0a5dccddddae2..24b2959a3fa01 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -22,7 +22,7 @@ use sys::{cvt, cvt_r}; pub struct AnonPipe(FileDesc); pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - weak! { fn pipe2(*mut c_int, c_int) -> c_int } + syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int } static INVALID: AtomicBool = ATOMIC_BOOL_INIT; let mut fds = [0; 2]; @@ -39,22 +39,20 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { !INVALID.load(Ordering::SeqCst) { - if let Some(pipe) = pipe2.get() { - // Note that despite calling a glibc function here we may still - // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to - // emulate on older kernels, so if you happen to be running on - // an older kernel you may see `pipe2` as a symbol but still not - // see the syscall. - match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { - Ok(_) => { - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))); - } - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { - INVALID.store(true, Ordering::SeqCst); - } - Err(e) => return Err(e), + // Note that despite calling a glibc function here we may still + // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to + // emulate on older kernels, so if you happen to be running on + // an older kernel you may see `pipe2` as a symbol but still not + // see the syscall. + match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { + Ok(_) => { + return Ok((AnonPipe(FileDesc::new(fds[0])), + AnonPipe(FileDesc::new(fds[1])))); + } + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { + INVALID.store(true, Ordering::SeqCst); } + Err(e) => return Err(e), } } cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs index 18944be58ee7e..3b73e3b7c50cc 100644 --- a/src/libstd/sys/unix/weak.rs +++ b/src/libstd/sys/unix/weak.rs @@ -77,3 +77,55 @@ unsafe fn fetch(name: &str) -> usize { }; libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize } + +#[cfg(not(target_os = "linux"))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name: $t),*) -> $ret { + use libc; + + weak! { fn $name($($t),*) -> $ret } + + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + libc::ENOSYS + } + } + ) +} + +#[cfg(target_os = "linux")] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name:$t),*) -> $ret { + // This like a hack, but concat_idents only accepts idents + // (not paths). + use libc::*; + + syscall( + concat_idents!(SYS_, $name), + $(::sys::weak::SyscallParam::to_param($arg_name)),* + ) as $ret + } + ) +} + +#[cfg(target_os = "linux")] +pub trait SyscallParam { + fn to_param(self) -> libc::c_long; +} + +#[cfg(target_os = "linux")] +impl SyscallParam for libc::c_int { + fn to_param(self) -> libc::c_long { + self as libc::c_long + } +} + +#[cfg(target_os = "linux")] +impl SyscallParam for *mut T { + fn to_param(self) -> libc::c_long { + unsafe { mem::transmute(self) } + } +} From da47bd3ae01f9a651b652bb141685b128c5058b0 Mon Sep 17 00:00:00 2001 From: Adrian Budau Date: Thu, 20 Dec 2018 13:29:04 +0200 Subject: [PATCH 2/3] Fix typo in comment --- src/libstd/sys/unix/weak.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs index 3b73e3b7c50cc..ab75a39eecc10 100644 --- a/src/libstd/sys/unix/weak.rs +++ b/src/libstd/sys/unix/weak.rs @@ -99,7 +99,7 @@ macro_rules! syscall { macro_rules! syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name:$t),*) -> $ret { - // This like a hack, but concat_idents only accepts idents + // This looks like a hack, but concat_idents only accepts idents // (not paths). use libc::*; From bf172c532af44628e3c3323a5f8a8c1726ffbd30 Mon Sep 17 00:00:00 2001 From: Adrian Budau Date: Fri, 21 Dec 2018 15:53:37 +0200 Subject: [PATCH 3/3] Properly report ENOSYS by modifying errno --- src/libstd/sys/unix/os.rs | 15 ++++++++++++++- src/libstd/sys/unix/weak.rs | 25 ++++--------------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 03e81a720dc64..6e8ee44599406 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -67,7 +67,8 @@ pub fn errno() -> i32 { } /// Sets the platform-specific value of errno -#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] // only needed for readdir so far +#[cfg(all(not(target_os = "linux"), + not(target_os = "dragonfly")))] // needed for readdir and syscall! pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int @@ -84,6 +85,18 @@ pub fn errno() -> i32 { unsafe { errno as i32 } } +#[cfg(target_os = "dragonfly")] +pub fn set_errno(e: i32) { + extern { + #[thread_local] + static mut errno: c_int; + } + + unsafe { + errno = e; + } +} + /// Gets a detailed string description for the given error number. pub fn error_string(errno: i32) -> String { extern { diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs index ab75a39eecc10..7d293f1c47a9a 100644 --- a/src/libstd/sys/unix/weak.rs +++ b/src/libstd/sys/unix/weak.rs @@ -83,13 +83,15 @@ macro_rules! syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( unsafe fn $name($($arg_name: $t),*) -> $ret { use libc; + use super::os; weak! { fn $name($($t),*) -> $ret } if let Some(fun) = $name.get() { fun($($arg_name),*) } else { - libc::ENOSYS + os::set_errno(libc::ENOSYS); + -1 } } ) @@ -105,27 +107,8 @@ macro_rules! syscall { syscall( concat_idents!(SYS_, $name), - $(::sys::weak::SyscallParam::to_param($arg_name)),* + $($arg_name as c_long),* ) as $ret } ) } - -#[cfg(target_os = "linux")] -pub trait SyscallParam { - fn to_param(self) -> libc::c_long; -} - -#[cfg(target_os = "linux")] -impl SyscallParam for libc::c_int { - fn to_param(self) -> libc::c_long { - self as libc::c_long - } -} - -#[cfg(target_os = "linux")] -impl SyscallParam for *mut T { - fn to_param(self) -> libc::c_long { - unsafe { mem::transmute(self) } - } -}