Skip to content

Commit 214fae3

Browse files
feat: I/O safety pipe, pipe2 & write
1 parent 996db47 commit 214fae3

15 files changed

+86
-135
lines changed

src/pty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl io::Read for PtyMaster {
7171

7272
impl io::Write for PtyMaster {
7373
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
74-
unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from)
74+
unistd::write(&self.0, buf).map_err(io::Error::from)
7575
}
7676
fn flush(&mut self) -> io::Result<()> {
7777
Ok(())
@@ -86,7 +86,7 @@ impl io::Read for &PtyMaster {
8686

8787
impl io::Write for &PtyMaster {
8888
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
89-
unistd::write(self.0.as_raw_fd(), buf).map_err(io::Error::from)
89+
unistd::write(&self.0, buf).map_err(io::Error::from)
9090
}
9191
fn flush(&mut self) -> io::Result<()> {
9292
Ok(())

src/sys/epoll.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl EpollEvent {
8787
/// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
8888
///
8989
/// // Arm eventfd & Time wait
90-
/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?;
90+
/// write(&eventfd, &1u64.to_ne_bytes())?;
9191
/// let now = Instant::now();
9292
///
9393
/// // Wait on event

src/sys/select.rs

+5-16
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,8 @@ where
322322
mod tests {
323323
use super::*;
324324
use crate::sys::time::{TimeVal, TimeValLike};
325-
use crate::unistd::{close, pipe, write};
326-
use std::os::unix::io::{FromRawFd, OwnedFd, RawFd};
325+
use crate::unistd::{pipe, write};
326+
use std::os::unix::io::RawFd;
327327

328328
#[test]
329329
fn fdset_insert() {
@@ -466,12 +466,9 @@ mod tests {
466466
#[test]
467467
fn test_select() {
468468
let (r1, w1) = pipe().unwrap();
469-
let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
470-
let w1 = unsafe { OwnedFd::from_raw_fd(w1) };
471469
let (r2, _w2) = pipe().unwrap();
472-
let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
473470

474-
write(w1.as_raw_fd(), b"hi!").unwrap();
471+
write(&w1, b"hi!").unwrap();
475472
let mut fd_set = FdSet::new();
476473
fd_set.insert(&r1);
477474
fd_set.insert(&r2);
@@ -483,18 +480,14 @@ mod tests {
483480
);
484481
assert!(fd_set.contains(&r1));
485482
assert!(!fd_set.contains(&r2));
486-
close(_w2).unwrap();
487483
}
488484

489485
#[test]
490486
fn test_select_nfds() {
491487
let (r1, w1) = pipe().unwrap();
492488
let (r2, _w2) = pipe().unwrap();
493-
let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
494-
let w1 = unsafe { OwnedFd::from_raw_fd(w1) };
495-
let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
496489

497-
write(w1.as_raw_fd(), b"hi!").unwrap();
490+
write(&w1, b"hi!").unwrap();
498491
let mut fd_set = FdSet::new();
499492
fd_set.insert(&r1);
500493
fd_set.insert(&r2);
@@ -521,16 +514,13 @@ mod tests {
521514
}
522515
assert!(fd_set.contains(&r1));
523516
assert!(!fd_set.contains(&r2));
524-
close(_w2).unwrap();
525517
}
526518

527519
#[test]
528520
fn test_select_nfds2() {
529521
let (r1, w1) = pipe().unwrap();
530-
write(w1, b"hi!").unwrap();
522+
write(&w1, b"hi!").unwrap();
531523
let (r2, _w2) = pipe().unwrap();
532-
let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
533-
let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
534524
let mut fd_set = FdSet::new();
535525
fd_set.insert(&r1);
536526
fd_set.insert(&r2);
@@ -549,6 +539,5 @@ mod tests {
549539
);
550540
assert!(fd_set.contains(&r1));
551541
assert!(!fd_set.contains(&r2));
552-
close(_w2).unwrap();
553542
}
554543
}

src/sys/socket/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1479,7 +1479,7 @@ impl<'a> ControlMessage<'a> {
14791479
/// let (r, w) = pipe().unwrap();
14801480
///
14811481
/// let iov = [IoSlice::new(b"hello")];
1482-
/// let fds = [r];
1482+
/// let fds = [r.as_raw_fd()];
14831483
/// let cmsg = ControlMessage::ScmRights(&fds);
14841484
/// sendmsg::<()>(fd1.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None).unwrap();
14851485
/// ```
@@ -1496,7 +1496,7 @@ impl<'a> ControlMessage<'a> {
14961496
/// let (r, w) = pipe().unwrap();
14971497
///
14981498
/// let iov = [IoSlice::new(b"hello")];
1499-
/// let fds = [r];
1499+
/// let fds = [r.as_raw_fd()];
15001500
/// let cmsg = ControlMessage::ScmRights(&fds);
15011501
/// sendmsg(fd.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap();
15021502
/// ```

src/unistd.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use std::ffi::{CString, OsStr};
3535
use std::os::unix::ffi::OsStrExt;
3636
use std::os::unix::ffi::OsStringExt;
3737
use std::os::unix::io::RawFd;
38-
use std::os::unix::io::{AsFd, AsRawFd};
38+
use std::os::unix::io::{AsFd, AsRawFd, OwnedFd};
3939
use std::path::PathBuf;
4040
use std::{fmt, mem, ptr};
4141

@@ -260,7 +260,7 @@ impl ForkResult {
260260
/// }
261261
/// Ok(ForkResult::Child) => {
262262
/// // Unsafe to use `println!` (or `unwrap`) here. See Safety.
263-
/// write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok();
263+
/// write(std::io::stdout(), "I'm a new child process\n".as_bytes()).ok();
264264
/// unsafe { libc::_exit(0) };
265265
/// }
266266
/// Err(_) => println!("Fork failed"),
@@ -1115,9 +1115,13 @@ pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
11151115
/// Write to a raw file descriptor.
11161116
///
11171117
/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
1118-
pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
1118+
pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> Result<usize> {
11191119
let res = unsafe {
1120-
libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t)
1120+
libc::write(
1121+
fd.as_fd().as_raw_fd(),
1122+
buf.as_ptr() as *const c_void,
1123+
buf.len() as size_t,
1124+
)
11211125
};
11221126

11231127
Errno::result(res).map(|r| r as usize)
@@ -1189,14 +1193,15 @@ pub fn lseek64(
11891193
/// Create an interprocess channel.
11901194
///
11911195
/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
1192-
pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> {
1193-
let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
1196+
pub fn pipe() -> std::result::Result<(OwnedFd, OwnedFd), Error> {
1197+
let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit();
11941198

11951199
let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) };
11961200

11971201
Error::result(res)?;
11981202

1199-
unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
1203+
let [read, write] = unsafe { fds.assume_init() };
1204+
Ok((read, write))
12001205
}
12011206

12021207
feature! {
@@ -1230,15 +1235,16 @@ feature! {
12301235
target_os = "openbsd",
12311236
target_os = "solaris"
12321237
))]
1233-
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
1234-
let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
1238+
pub fn pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd)> {
1239+
let mut fds = mem::MaybeUninit::<[OwnedFd; 2]>::uninit();
12351240

12361241
let res =
12371242
unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) };
12381243

12391244
Errno::result(res)?;
12401245

1241-
unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
1246+
let [read, write] = unsafe { fds.assume_init() };
1247+
Ok((read, write))
12421248
}
12431249

12441250
/// Truncate a file to a specified length

test/sys/test_select.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@ use nix::sys::select::*;
22
use nix::sys::signal::SigSet;
33
use nix::sys::time::{TimeSpec, TimeValLike};
44
use nix::unistd::{pipe, write};
5-
use std::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, OwnedFd};
5+
use std::os::unix::io::{AsRawFd, BorrowedFd};
66

77
#[test]
88
pub fn test_pselect() {
99
let _mtx = crate::SIGNAL_MTX.lock();
1010

1111
let (r1, w1) = pipe().unwrap();
12-
write(w1, b"hi!").unwrap();
13-
let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
12+
write(&w1, b"hi!").unwrap();
1413
let (r2, _w2) = pipe().unwrap();
15-
let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
1614

1715
let mut fd_set = FdSet::new();
1816
fd_set.insert(&r1);
@@ -31,10 +29,8 @@ pub fn test_pselect() {
3129
#[test]
3230
pub fn test_pselect_nfds2() {
3331
let (r1, w1) = pipe().unwrap();
34-
write(w1, b"hi!").unwrap();
35-
let r1 = unsafe { OwnedFd::from_raw_fd(r1) };
32+
write(&w1, b"hi!").unwrap();
3633
let (r2, _w2) = pipe().unwrap();
37-
let r2 = unsafe { OwnedFd::from_raw_fd(r2) };
3834

3935
let mut fd_set = FdSet::new();
4036
fd_set.insert(&r1);

test/sys/test_socket.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ pub fn test_socketpair() {
200200
SockFlag::empty(),
201201
)
202202
.unwrap();
203-
write(fd1.as_raw_fd(), b"hello").unwrap();
203+
write(&fd1, b"hello").unwrap();
204204
let mut buf = [0; 5];
205205
read(fd2.as_raw_fd(), &mut buf).unwrap();
206206

@@ -757,7 +757,7 @@ pub fn test_scm_rights() {
757757

758758
{
759759
let iov = [IoSlice::new(b"hello")];
760-
let fds = [r];
760+
let fds = [r.as_raw_fd()];
761761
let cmsg = ControlMessage::ScmRights(&fds);
762762
assert_eq!(
763763
sendmsg::<()>(
@@ -770,7 +770,6 @@ pub fn test_scm_rights() {
770770
.unwrap(),
771771
5
772772
);
773-
close(r).unwrap();
774773
}
775774

776775
{
@@ -803,12 +802,11 @@ pub fn test_scm_rights() {
803802

804803
let received_r = received_r.expect("Did not receive passed fd");
805804
// Ensure that the received file descriptor works
806-
write(w.as_raw_fd(), b"world").unwrap();
805+
write(&w, b"world").unwrap();
807806
let mut buf = [0u8; 5];
808807
read(received_r.as_raw_fd(), &mut buf).unwrap();
809808
assert_eq!(&buf[..], b"world");
810809
close(received_r).unwrap();
811-
close(w).unwrap();
812810
}
813811

814812
// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
@@ -1451,7 +1449,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
14511449
gid: getgid().as_raw(),
14521450
}
14531451
.into();
1454-
let fds = [r];
1452+
let fds = [r.as_raw_fd()];
14551453
let cmsgs = [
14561454
ControlMessage::ScmCredentials(&cred),
14571455
ControlMessage::ScmRights(&fds),
@@ -1467,7 +1465,6 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
14671465
.unwrap(),
14681466
5
14691467
);
1470-
close(r).unwrap();
14711468
}
14721469

14731470
{
@@ -1510,12 +1507,11 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
15101507

15111508
let received_r = received_r.expect("Did not receive passed fd");
15121509
// Ensure that the received file descriptor works
1513-
write(w.as_raw_fd(), b"world").unwrap();
1510+
write(&w, b"world").unwrap();
15141511
let mut buf = [0u8; 5];
15151512
read(received_r.as_raw_fd(), &mut buf).unwrap();
15161513
assert_eq!(&buf[..], b"world");
15171514
close(received_r).unwrap();
1518-
close(w).unwrap();
15191515
}
15201516

15211517
// Test creating and using named unix domain sockets
@@ -1548,7 +1544,7 @@ pub fn test_named_unixdomain() {
15481544
)
15491545
.expect("socket failed");
15501546
connect(s2.as_raw_fd(), &sockaddr).expect("connect failed");
1551-
write(s2.as_raw_fd(), b"hello").expect("write failed");
1547+
write(&s2, b"hello").expect("write failed");
15521548
});
15531549

15541550
let s3 = accept(s1.as_raw_fd()).expect("accept failed");

test/sys/test_sockopt.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use nix::sys::socket::{
55
SockProtocol, SockType,
66
};
77
use rand::{thread_rng, Rng};
8-
use std::os::unix::io::AsRawFd;
8+
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
99

1010
// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
1111
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",))]
@@ -151,7 +151,8 @@ fn test_so_tcp_maxseg() {
151151
.unwrap();
152152
connect(ssock.as_raw_fd(), &sock_addr).unwrap();
153153
let rsess = accept(rsock.as_raw_fd()).unwrap();
154-
write(rsess, b"hello").unwrap();
154+
let rsess = unsafe { OwnedFd::from_raw_fd(rsess) };
155+
write(&rsess, b"hello").unwrap();
155156
let actual = getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap();
156157
// Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
157158
// TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
@@ -185,7 +186,6 @@ fn test_so_type() {
185186
#[test]
186187
fn test_so_type_unknown() {
187188
use nix::errno::Errno;
188-
use std::os::unix::io::{FromRawFd, OwnedFd};
189189

190190
require_capability!("test_so_type", CAP_NET_RAW);
191191
let raw_fd = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_PACKET, 0) };

test/sys/test_termios.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use nix::unistd::{read, write};
1111
fn write_all<Fd: AsFd>(f: Fd, buf: &[u8]) {
1212
let mut len = 0;
1313
while len < buf.len() {
14-
len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap();
14+
len += write(f.as_fd(), &buf[len..]).unwrap();
1515
}
1616
}
1717

0 commit comments

Comments
 (0)