Skip to content

Commit cc53f4e

Browse files
committed
Fix pipe2 and accept4 on static linked executables on linux (like musl).
1 parent e7b4bc3 commit cc53f4e

File tree

4 files changed

+81
-27
lines changed

4 files changed

+81
-27
lines changed

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@
250250
#![feature(cfg_target_vendor)]
251251
#![feature(char_error_internals)]
252252
#![feature(compiler_builtins_lib)]
253+
#![feature(concat_idents)]
253254
#![feature(const_int_ops)]
254255
#![feature(const_ip)]
255256
#![feature(const_raw_ptr_deref)]

src/libstd/sys/unix/net.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -203,18 +203,21 @@ impl Socket {
203203
// Linux. This was added in 2.6.28, however, and because we support
204204
// 2.6.18 we must detect this support dynamically.
205205
if cfg!(target_os = "linux") {
206-
weak! {
207-
fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
206+
syscall! {
207+
fn accept4(
208+
fd: c_int,
209+
addr: *mut sockaddr,
210+
addr_len: *mut socklen_t,
211+
flags: c_int
212+
) -> c_int
208213
}
209-
if let Some(accept) = accept4.get() {
210-
let res = cvt_r(|| unsafe {
211-
accept(self.0.raw(), storage, len, SOCK_CLOEXEC)
212-
});
213-
match res {
214-
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
215-
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
216-
Err(e) => return Err(e),
217-
}
214+
let res = cvt_r(|| unsafe {
215+
accept4(self.0.raw(), storage, len, SOCK_CLOEXEC)
216+
});
217+
match res {
218+
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
219+
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
220+
Err(e) => return Err(e),
218221
}
219222
}
220223

src/libstd/sys/unix/pipe.rs

+14-16
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use sys::{cvt, cvt_r};
2222
pub struct AnonPipe(FileDesc);
2323

2424
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
25-
weak! { fn pipe2(*mut c_int, c_int) -> c_int }
25+
syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int }
2626
static INVALID: AtomicBool = ATOMIC_BOOL_INIT;
2727

2828
let mut fds = [0; 2];
@@ -39,22 +39,20 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
3939
!INVALID.load(Ordering::SeqCst)
4040
{
4141

42-
if let Some(pipe) = pipe2.get() {
43-
// Note that despite calling a glibc function here we may still
44-
// get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
45-
// emulate on older kernels, so if you happen to be running on
46-
// an older kernel you may see `pipe2` as a symbol but still not
47-
// see the syscall.
48-
match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
49-
Ok(_) => {
50-
return Ok((AnonPipe(FileDesc::new(fds[0])),
51-
AnonPipe(FileDesc::new(fds[1]))));
52-
}
53-
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
54-
INVALID.store(true, Ordering::SeqCst);
55-
}
56-
Err(e) => return Err(e),
42+
// Note that despite calling a glibc function here we may still
43+
// get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
44+
// emulate on older kernels, so if you happen to be running on
45+
// an older kernel you may see `pipe2` as a symbol but still not
46+
// see the syscall.
47+
match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
48+
Ok(_) => {
49+
return Ok((AnonPipe(FileDesc::new(fds[0])),
50+
AnonPipe(FileDesc::new(fds[1]))));
51+
}
52+
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
53+
INVALID.store(true, Ordering::SeqCst);
5754
}
55+
Err(e) => return Err(e),
5856
}
5957
}
6058
cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;

src/libstd/sys/unix/weak.rs

+52
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,55 @@ unsafe fn fetch(name: &str) -> usize {
7777
};
7878
libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
7979
}
80+
81+
#[cfg(not(target_os = "linux"))]
82+
macro_rules! syscall {
83+
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
84+
unsafe fn $name($($arg_name: $t),*) -> $ret {
85+
use libc;
86+
87+
weak! { fn $name($($t),*) -> $ret }
88+
89+
if let Some(fun) = $name.get() {
90+
fun($($arg_name),*)
91+
} else {
92+
libc::ENOSYS
93+
}
94+
}
95+
)
96+
}
97+
98+
#[cfg(target_os = "linux")]
99+
macro_rules! syscall {
100+
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
101+
unsafe fn $name($($arg_name:$t),*) -> $ret {
102+
// This like a hack, but concat_idents only accepts idents
103+
// (not paths).
104+
use libc::*;
105+
106+
syscall(
107+
concat_idents!(SYS_, $name),
108+
$(::sys::weak::SyscallParam::to_param($arg_name)),*
109+
) as $ret
110+
}
111+
)
112+
}
113+
114+
#[cfg(target_os = "linux")]
115+
pub trait SyscallParam {
116+
fn to_param(self) -> libc::c_long;
117+
}
118+
119+
#[cfg(target_os = "linux")]
120+
impl SyscallParam for libc::c_int {
121+
fn to_param(self) -> libc::c_long {
122+
self as libc::c_long
123+
}
124+
}
125+
126+
#[cfg(target_os = "linux")]
127+
impl<T> SyscallParam for *mut T {
128+
fn to_param(self) -> libc::c_long {
129+
unsafe { mem::transmute(self) }
130+
}
131+
}

0 commit comments

Comments
 (0)