Skip to content

Commit ebd5431

Browse files
feat: I/O safety pipe, pipe2 & write
1 parent 842142f commit ebd5431

11 files changed

+55
-90
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/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/unistd.rs

+15-9
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

@@ -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

+2-6
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ 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

+2-6
Original file line numberDiff line numberDiff line change
@@ -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
@@ -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

test/sys/test_uio.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rand::distributions::Alphanumeric;
44
use rand::{thread_rng, Rng};
55
use std::fs::OpenOptions;
66
use std::io::IoSlice;
7-
use std::os::unix::io::{FromRawFd, OwnedFd};
7+
use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd};
88
use std::{cmp, iter};
99

1010
#[cfg(not(target_os = "redox"))]
@@ -241,10 +241,10 @@ fn test_process_vm_readv() {
241241
let (r, w) = pipe().unwrap();
242242
match unsafe { fork() }.expect("Error: Fork Failed") {
243243
Parent { child } => {
244-
close(w).unwrap();
244+
drop(w);
245245
// wait for child
246-
read(r, &mut [0u8]).unwrap();
247-
close(r).unwrap();
246+
read(r.as_raw_fd(), &mut [0u8]).unwrap();
247+
drop(r);
248248

249249
let ptr = vector.as_ptr() as usize;
250250
let remote_iov = RemoteIoVec { base: ptr, len: 5 };
@@ -263,12 +263,12 @@ fn test_process_vm_readv() {
263263
assert_eq!(20u8, buf.iter().sum());
264264
}
265265
Child => {
266-
let _ = close(r);
266+
drop(r);
267267
for i in &mut vector {
268268
*i += 1;
269269
}
270270
let _ = write(w, b"\0");
271-
let _ = close(w);
271+
drop(w);
272272
loop {
273273
pause();
274274
}

test/test_fcntl.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -309,12 +309,9 @@ mod linux_android {
309309
assert_eq!(2, res);
310310

311311
let mut buf = [0u8; 1024];
312-
assert_eq!(2, read(rd, &mut buf).unwrap());
312+
assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap());
313313
assert_eq!(b"f1", &buf[0..2]);
314314
assert_eq!(7, offset);
315-
316-
close(rd).unwrap();
317-
close(wr).unwrap();
318315
}
319316

320317
#[test]
@@ -336,11 +333,6 @@ mod linux_android {
336333
// Check all the bytes are still at rd1.
337334
assert_eq!(3, read(rd1, &mut buf).unwrap());
338335
assert_eq!(b"abc", &buf[0..3]);
339-
340-
close(rd1).unwrap();
341-
close(wr1).unwrap();
342-
close(rd2).unwrap();
343-
close(wr2).unwrap();
344336
}
345337

346338
#[test]
@@ -359,9 +351,6 @@ mod linux_android {
359351
let mut buf = [0u8; 32];
360352
assert_eq!(6, read(rd, &mut buf).unwrap());
361353
assert_eq!(b"abcdef", &buf[0..6]);
362-
363-
close(rd).unwrap();
364-
close(wr).unwrap();
365354
}
366355

367356
#[cfg(target_os = "linux")]

test/test_poll.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,12 @@ fn test_poll() {
2828
assert_eq!(nfds, 0);
2929
assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
3030

31-
write(w, b".").unwrap();
31+
write(&w, b".").unwrap();
3232

3333
// Poll a readable pipe. Should return an event.
3434
let nfds = poll(&mut fds, 100).unwrap();
3535
assert_eq!(nfds, 1);
3636
assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
37-
close(w).unwrap();
3837
}
3938

4039
// ppoll(2) is the same as poll except for how it handles timeouts and signals.
@@ -63,13 +62,12 @@ fn test_ppoll() {
6362
assert_eq!(nfds, 0);
6463
assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
6564

66-
write(w, b".").unwrap();
65+
write(&w, b".").unwrap();
6766

6867
// Poll a readable pipe. Should return an event.
6968
let nfds = ppoll(&mut fds, Some(timeout), None).unwrap();
7069
assert_eq!(nfds, 1);
7170
assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
72-
close(w).unwrap();
7371
}
7472

7573
#[test]

test/test_pty.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::fs::File;
2-
use std::io::{Read, Write};
2+
use std::io::{stdout, Read, Write};
33
use std::os::unix::prelude::*;
44
use std::path::Path;
55

6-
use libc::{_exit, STDOUT_FILENO};
6+
use libc::_exit;
77
use nix::fcntl::{open, OFlag};
88
use nix::pty::*;
99
use nix::sys::stat;
@@ -185,7 +185,7 @@ fn test_openpty() {
185185
// Writing to one should be readable on the other one
186186
let string = "foofoofoo\n";
187187
let mut buf = [0u8; 10];
188-
write(pty.master.as_raw_fd(), string.as_bytes()).unwrap();
188+
write(&pty.master, string.as_bytes()).unwrap();
189189
crate::read_exact(&pty.slave, &mut buf);
190190

191191
assert_eq!(&buf, string.as_bytes());
@@ -199,7 +199,7 @@ fn test_openpty() {
199199
let string2 = "barbarbarbar\n";
200200
let echoed_string2 = "barbarbarbar\r\n";
201201
let mut buf = [0u8; 14];
202-
write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap();
202+
write(&pty.slave, string2.as_bytes()).unwrap();
203203
crate::read_exact(&pty.master, &mut buf);
204204

205205
assert_eq!(&buf, echoed_string2.as_bytes());
@@ -224,7 +224,7 @@ fn test_openpty_with_termios() {
224224
// Writing to one should be readable on the other one
225225
let string = "foofoofoo\n";
226226
let mut buf = [0u8; 10];
227-
write(pty.master.as_raw_fd(), string.as_bytes()).unwrap();
227+
write(&pty.master, string.as_bytes()).unwrap();
228228
crate::read_exact(&pty.slave, &mut buf);
229229

230230
assert_eq!(&buf, string.as_bytes());
@@ -237,7 +237,7 @@ fn test_openpty_with_termios() {
237237
let string2 = "barbarbarbar\n";
238238
let echoed_string2 = "barbarbarbar\n";
239239
let mut buf = [0u8; 13];
240-
write(pty.slave.as_raw_fd(), string2.as_bytes()).unwrap();
240+
write(&pty.slave, string2.as_bytes()).unwrap();
241241
crate::read_exact(&pty.master, &mut buf);
242242

243243
assert_eq!(&buf, echoed_string2.as_bytes());
@@ -258,7 +258,7 @@ fn test_forkpty() {
258258
let pty = unsafe { forkpty(None, None).unwrap() };
259259
match pty.fork_result {
260260
Child => {
261-
write(STDOUT_FILENO, string.as_bytes()).unwrap();
261+
write(stdout(), string.as_bytes()).unwrap();
262262
pause(); // we need the child to stay alive until the parent calls read
263263
unsafe {
264264
_exit(0);

0 commit comments

Comments
 (0)