From d15418586ca78ead4f87ad18fcffa3550c1b169e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 30 Jun 2021 21:44:30 -0700 Subject: [PATCH 01/28] I/O safety. Introduce `OwnedFd` and `BorrowedFd`, and the `AsFd` trait, and implementations of `AsFd`, `From` and `From for OwnedFd` for relevant types, along with Windows counterparts for handles and sockets. Tracking issue: - RFC: - --- library/std/src/lib.rs | 1 + library/std/src/net/udp/tests.rs | 3 +- library/std/src/os/unix/io/fd.rs | 329 +++++++++++++++ library/std/src/os/unix/io/mod.rs | 56 +++ library/std/src/os/unix/{io.rs => io/raw.rs} | 10 +- library/std/src/os/unix/net/datagram.rs | 44 +- library/std/src/os/unix/net/listener.rs | 14 +- library/std/src/os/unix/net/raw_fd.rs | 8 +- library/std/src/os/unix/net/stream.rs | 40 +- library/std/src/os/unix/process.rs | 14 +- library/std/src/os/wasi/fs.rs | 30 +- library/std/src/os/wasi/io/fd.rs | 280 +++++++++++++ library/std/src/os/wasi/io/mod.rs | 12 + library/std/src/os/wasi/{io.rs => io/raw.rs} | 124 +++--- library/std/src/os/wasi/mod.rs | 1 + library/std/src/os/wasi/net/mod.rs | 8 + library/std/src/os/wasi/net/raw_fd.rs | 45 ++ library/std/src/os/windows/io/handle.rs | 390 ++++++++++++++++++ library/std/src/os/windows/io/mod.rs | 56 +++ .../std/src/os/windows/{io.rs => io/raw.rs} | 27 +- library/std/src/os/windows/io/socket.rs | 212 ++++++++++ library/std/src/os/windows/process.rs | 18 +- library/std/src/os/windows/thread.rs | 4 +- library/std/src/sys/unix/fd.rs | 115 +++--- library/std/src/sys/unix/fd/tests.rs | 3 +- library/std/src/sys/unix/fs.rs | 77 +++- library/std/src/sys/unix/net.rs | 92 +++-- library/std/src/sys/unix/pipe.rs | 63 ++- .../src/sys/unix/process/process_common.rs | 15 +- library/std/src/sys/unix/stdio.rs | 65 ++- library/std/src/sys/wasi/fd.rs | 138 ++++--- library/std/src/sys/wasi/fs.rs | 49 ++- library/std/src/sys/wasi/net.rs | 125 ++++-- library/std/src/sys/wasi/stdio.rs | 19 +- library/std/src/sys/windows/fs.rs | 73 +++- library/std/src/sys/windows/handle.rs | 122 +++--- library/std/src/sys/windows/net.rs | 106 +++-- library/std/src/sys/windows/os.rs | 2 +- library/std/src/sys/windows/pipe.rs | 17 +- library/std/src/sys/windows/process.rs | 41 +- library/std/src/sys/windows/stdio.rs | 21 +- library/std/src/sys/windows/thread.rs | 5 +- library/std/src/sys_common/net.rs | 42 +- 43 files changed, 2360 insertions(+), 556 deletions(-) create mode 100644 library/std/src/os/unix/io/fd.rs create mode 100644 library/std/src/os/unix/io/mod.rs rename library/std/src/os/unix/{io.rs => io/raw.rs} (96%) create mode 100644 library/std/src/os/wasi/io/fd.rs create mode 100644 library/std/src/os/wasi/io/mod.rs rename library/std/src/os/wasi/{io.rs => io/raw.rs} (65%) create mode 100644 library/std/src/os/wasi/net/mod.rs create mode 100644 library/std/src/os/wasi/net/raw_fd.rs create mode 100644 library/std/src/os/windows/io/handle.rs create mode 100644 library/std/src/os/windows/io/mod.rs rename library/std/src/os/windows/{io.rs => io/raw.rs} (88%) create mode 100644 library/std/src/os/windows/io/socket.rs diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5e91a0cdbd6b5..befb40cd2ed90 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -285,6 +285,7 @@ #![feature(int_log)] #![feature(into_future)] #![feature(intra_doc_pointers)] +#![feature(io_safety)] #![feature(iter_zip)] #![feature(lang_items)] #![feature(linkage)] diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index fbed3d32d451a..a51113dd9e749 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -2,7 +2,6 @@ use crate::io::ErrorKind; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; -use crate::sys_common::AsInner; use crate::thread; use crate::time::{Duration, Instant}; @@ -173,7 +172,7 @@ fn debug() { let socket_addr = next_test_ip4(); let udpsock = t!(UdpSocket::bind(&socket_addr)); - let udpsock_inner = udpsock.0.socket().as_inner(); + let udpsock_inner = udpsock.0.socket().as_raw(); let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); assert_eq!(format!("{:?}", udpsock), compare); } diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs new file mode 100644 index 0000000000000..5bf6369122b97 --- /dev/null +++ b/library/std/src/os/unix/io/fd.rs @@ -0,0 +1,329 @@ +//! Owned and borrowed file descriptors. + +#![unstable(feature = "io_safety", issue = "87074")] + +use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::fmt; +use crate::fs; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::os::raw; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// A borrowed file descriptor. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the file descriptor. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as an argument, it is not captured or consumed, and it never has the +/// value `-1`. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct BorrowedFd<'fd> { + raw: RawFd, + _phantom: PhantomData<&'fd OwnedFd>, +} + +/// An owned file descriptor. +/// +/// This closes the file descriptor on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as a consumed argument or returned as an owned value, and it never +/// has the value `-1`. +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OwnedFd { + raw: RawFd, +} + +impl BorrowedFd<'_> { + /// Return a `BorrowedFd` holding the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must remain open for the duration of + /// the returned `BorrowedFd`, and it must not have the value `-1`. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub unsafe fn borrow_raw_fd(raw: RawFd) -> Self { + assert_ne!(raw, -1_i32 as RawFd); + Self { raw, _phantom: PhantomData } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsRawFd for BorrowedFd<'_> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.raw + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsRawFd for OwnedFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.raw + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl IntoRawFd for OwnedFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + let raw = self.raw; + forget(self); + raw + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl FromRawFd for OwnedFd { + /// Constructs a new instance of `Self` from the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be open and suitable for assuming + /// ownership. + #[inline] + unsafe fn from_raw_fd(raw: RawFd) -> Self { + assert_ne!(raw, -1i32); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + Self { raw } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl Drop for OwnedFd { + #[inline] + fn drop(&mut self) { + unsafe { + // Note that errors are ignored when closing a file descriptor. The + // reason for this is that if an error occurs we don't actually know if + // the file descriptor was closed or not, and if we retried (for + // something like EINTR), we might close another valid file descriptor + // opened after we closed ours. + let _ = libc::close(self.raw as raw::c_int); + } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Debug for BorrowedFd<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedFd").field("fd", &self.raw).finish() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Debug for OwnedFd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedFd").field("fd", &self.raw).finish() + } +} + +/// A trait to borrow the file descriptor from an underlying object. +/// +/// This is only available on unix platforms and must be imported in order to +/// call the method. Windows platforms have a corresponding `AsHandle` and +/// `AsSocket` set of traits. +#[unstable(feature = "io_safety", issue = "87074")] +pub trait AsFd { + /// Borrows the file descriptor. + /// + /// # Example + /// + /// ```rust,no_run + /// #![feature(io_safety)] + /// use std::fs::File; + /// # use std::io; + /// use std::os::unix::io::{AsFd, BorrowedFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[unstable(feature = "io_safety", issue = "87074")] + fn as_fd(&self) -> BorrowedFd<'_>; +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for BorrowedFd<'_> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + *self + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for OwnedFd { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for fs::File { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(file: fs::File) -> OwnedFd { + file.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for fs::File { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::TcpStream { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { + tcp_stream.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::TcpStream { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::TcpListener { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { + tcp_listener.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::TcpListener { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::UdpSocket { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { + udp_socket.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::UdpSocket { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::process::ChildStdin { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { + child_stdin.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::process::ChildStdout { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { + child_stdout.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::process::ChildStderr { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { + child_stderr.into_inner().into_inner().into_inner() + } +} diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs new file mode 100644 index 0000000000000..06f47cbb31f01 --- /dev/null +++ b/library/std/src/os/unix/io/mod.rs @@ -0,0 +1,56 @@ +//! Unix-specific extensions to general I/O primitives. +//! +//! Just like raw pointers, raw file descriptors point to resources with +//! dynamic lifetimes, and they can dangle if they outlive their resources +//! or be forged if they're created from invalid values. +//! +//! This module provides three types for representing file descriptors, +//! with different ownership properties: raw, borrowed, and owned, which are +//! analogous to types used for representing pointers: +//! +//! | Type | Analogous to | +//! | ------------------ | ------------ | +//! | [`RawFd`] | `*const _` | +//! | [`BorrowedFd<'a>`] | `&'a _` | +//! | [`OwnedFd`] | `Box<_>` | +//! +//! Like raw pointers, `RawFd` values are primitive values. And in new code, +//! they should be considered unsafe to do I/O on (analogous to dereferencing +//! them). Rust did not always provide this guidance, so existing code in the +//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Libraries are +//! encouraged to migrate, either by adding `unsafe` to APIs that dereference +//! `RawFd` values, or by using to `BorrowedFd` or `OwnedFd` instead. +//! +//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure +//! that they don't outlive the resource they point to. These are safe to +//! use. `BorrowedFd` values may be used in APIs which provide safe access to +//! any system call except for: +//! - `close`, because that would end the dynamic lifetime of the resource +//! without ending the lifetime of the file descriptor. +//! - `dup2`/`dup3`, in the second argument, because this argument is +//! closed and replaced with a new resource, which may break the assumptions +//! other code using that file descriptor. +//! This list doesn't include `mmap`, since `mmap` does do a proper borrow of +//! its file descriptor argument. That said, `mmap` is unsafe for other +//! reasons: it operates on raw pointers, and it has undefined behavior if the +//! underlying storage is mutated. Mutations may come from other processes, or +//! from the same process if the API provides `BorrowedFd` access, since as +//! mentioned earlier, `BorrowedFd` values may be used in APIs which provide +//! safe access to any system call. Consequently, code using `mmap` and +//! presenting a safe API must take full responsibility for ensuring that safe +//! Rust code cannot evoke undefined behavior through it. +//! +//! Like boxes, `OwnedFd` values conceptually own the resource they point to, +//! and free (close) it when they are dropped. +//! +//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd + +#![stable(feature = "rust1", since = "1.0.0")] + +mod fd; +mod raw; + +#[unstable(feature = "io_safety", issue = "87074")] +pub use fd::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::*; diff --git a/library/std/src/os/unix/io.rs b/library/std/src/os/unix/io/raw.rs similarity index 96% rename from library/std/src/os/unix/io.rs rename to library/std/src/os/unix/io/raw.rs index 07c30bfa9ed15..78ee706d41dee 100644 --- a/library/std/src/os/unix/io.rs +++ b/library/std/src/os/unix/io/raw.rs @@ -5,8 +5,8 @@ use crate::fs; use crate::io; use crate::os::raw; -use crate::sys; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::os::unix::io::OwnedFd; +use crate::sys_common::{AsInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -128,21 +128,21 @@ impl FromRawFd for RawFd { impl AsRawFd for fs::File { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } #[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for fs::File { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) + fs::File::from(OwnedFd::from_raw_fd(fd)) } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 9e39f70f68e69..f11eec18cc521 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -21,7 +21,7 @@ use super::{sockaddr_un, SocketAddr}; ))] use crate::io::{IoSlice, IoSliceMut}; use crate::net::Shutdown; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; @@ -106,7 +106,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::bind(socket.as_raw_fd(), &addr as *const _ as *const _, len as _))?; Ok(socket) } @@ -187,7 +187,7 @@ impl UnixDatagram { unsafe { let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::connect(self.as_raw_fd(), &addr as *const _ as *const _, len))?; } Ok(()) } @@ -229,7 +229,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } /// Returns the address of this socket's peer. @@ -253,7 +253,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) }) } fn recv_from_flags( @@ -264,7 +264,7 @@ impl UnixDatagram { let mut count = 0; let addr = SocketAddr::new(|addr, len| unsafe { count = libc::recvfrom( - *self.0.as_inner(), + self.as_raw_fd(), buf.as_mut_ptr() as *mut _, buf.len(), flags, @@ -462,7 +462,7 @@ impl UnixDatagram { let (addr, len) = sockaddr_un(path.as_ref())?; let count = cvt(libc::sendto( - *self.0.as_inner(), + self.as_raw_fd(), buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, @@ -881,7 +881,7 @@ impl UnixDatagram { impl AsRawFd for UnixDatagram { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() + self.0.as_inner().as_raw_fd() } } @@ -889,7 +889,7 @@ impl AsRawFd for UnixDatagram { impl FromRawFd for UnixDatagram { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) + UnixDatagram(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } } @@ -897,6 +897,30 @@ impl FromRawFd for UnixDatagram { impl IntoRawFd for UnixDatagram { #[inline] fn into_raw_fd(self) -> RawFd { - self.0.into_inner() + self.0.into_inner().into_inner().into_raw_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for UnixDatagram { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(unix_datagram: UnixDatagram) -> OwnedFd { + unsafe { OwnedFd::from_raw_fd(unix_datagram.into_raw_fd()) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for UnixDatagram { + #[inline] + fn from(owned: OwnedFd) -> Self { + unsafe { Self::from_raw_fd(owned.into_raw_fd()) } } } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index bdd08fe8380fa..9066c71794fad 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -1,5 +1,5 @@ use super::{sockaddr_un, SocketAddr, UnixStream}; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; @@ -74,8 +74,8 @@ impl UnixListener { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; + cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?; Ok(UnixListener(inner)) } @@ -150,7 +150,7 @@ impl UnixListener { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } /// Moves the socket into or out of nonblocking mode. @@ -242,7 +242,7 @@ impl UnixListener { impl AsRawFd for UnixListener { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() + self.0.as_inner().as_raw_fd() } } @@ -250,7 +250,7 @@ impl AsRawFd for UnixListener { impl FromRawFd for UnixListener { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) + UnixListener(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } } @@ -258,7 +258,7 @@ impl FromRawFd for UnixListener { impl IntoRawFd for UnixListener { #[inline] fn into_raw_fd(self) -> RawFd { - self.0.into_inner() + self.0.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/unix/net/raw_fd.rs b/library/std/src/os/unix/net/raw_fd.rs index b3f1284410124..017caeebf7243 100644 --- a/library/std/src/os/unix/net/raw_fd.rs +++ b/library/std/src/os/unix/net/raw_fd.rs @@ -1,4 +1,4 @@ -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::{net, sys}; @@ -8,7 +8,7 @@ macro_rules! impl_as_raw_fd { impl AsRawFd for net::$t { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_fd() } } )*}; @@ -21,7 +21,7 @@ macro_rules! impl_from_raw_fd { impl FromRawFd for net::$t { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> net::$t { - let socket = sys::net::Socket::from_inner(fd); + let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); net::$t::from_inner(sys_common::net::$t::from_inner(socket)) } } @@ -35,7 +35,7 @@ macro_rules! impl_into_raw_fd { impl IntoRawFd for net::$t { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_inner().into_raw_fd() } } )*}; diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index fba084375e5f8..4119de3c03cbe 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -13,7 +13,7 @@ use super::{sockaddr_un, SocketAddr}; use crate::fmt; use crate::io::{self, Initializer, IoSlice, IoSliceMut}; use crate::net::Shutdown; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[cfg(any( target_os = "android", target_os = "linux", @@ -28,7 +28,7 @@ use crate::os::unix::ucred; use crate::path::Path; use crate::sys::cvt; use crate::sys::net::Socket; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner}; use crate::time::Duration; #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] @@ -101,7 +101,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::connect(inner.as_raw_fd(), &addr as *const _ as *const _, len))?; Ok(UnixStream(inner)) } } @@ -167,7 +167,7 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.as_raw_fd(), addr, len) }) } /// Returns the socket address of the remote half of this connection. @@ -185,7 +185,7 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + SocketAddr::new(|addr, len| unsafe { libc::getpeername(self.as_raw_fd(), addr, len) }) } /// Gets the peer credentials for this Unix domain socket. @@ -659,7 +659,7 @@ impl<'a> io::Write for &'a UnixStream { impl AsRawFd for UnixStream { #[inline] fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() + self.0.as_raw_fd() } } @@ -667,7 +667,7 @@ impl AsRawFd for UnixStream { impl FromRawFd for UnixStream { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) + UnixStream(Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)))) } } @@ -675,6 +675,30 @@ impl FromRawFd for UnixStream { impl IntoRawFd for UnixStream { #[inline] fn into_raw_fd(self) -> RawFd { - self.0.into_inner() + self.0.into_raw_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for UnixStream { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(unix_stream: UnixStream) -> OwnedFd { + unsafe { OwnedFd::from_raw_fd(unix_stream.into_raw_fd()) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for UnixStream { + #[inline] + fn from(owned: OwnedFd) -> Self { + unsafe { Self::from_raw_fd(owned.into_raw_fd()) } } } diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 615290d270307..1e794842e3c11 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -321,7 +321,7 @@ impl ExitStatusExt for process::ExitStatusError { impl FromRawFd for process::Stdio { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { - let fd = sys::fd::FileDesc::new(fd); + let fd = sys::fd::FileDesc::from_raw_fd(fd); let io = sys::process::Stdio::Fd(fd); process::Stdio::from_inner(io) } @@ -331,7 +331,7 @@ impl FromRawFd for process::Stdio { impl AsRawFd for process::ChildStdin { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } @@ -339,7 +339,7 @@ impl AsRawFd for process::ChildStdin { impl AsRawFd for process::ChildStdout { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } @@ -347,7 +347,7 @@ impl AsRawFd for process::ChildStdout { impl AsRawFd for process::ChildStderr { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() + self.as_inner().as_raw_fd() } } @@ -355,7 +355,7 @@ impl AsRawFd for process::ChildStderr { impl IntoRawFd for process::ChildStdin { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } @@ -363,7 +363,7 @@ impl IntoRawFd for process::ChildStdin { impl IntoRawFd for process::ChildStdout { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } @@ -371,7 +371,7 @@ impl IntoRawFd for process::ChildStdout { impl IntoRawFd for process::ChildStderr { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index bd30d6ae3f333..3df27563e21e9 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -228,35 +228,35 @@ pub trait FileExt { impl FileExt for fs::File { fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - self.as_inner().fd().pread(bufs, offset) + self.as_inner().as_inner().pread(bufs, offset) } fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - self.as_inner().fd().pwrite(bufs, offset) + self.as_inner().as_inner().pwrite(bufs, offset) } fn tell(&self) -> io::Result { - self.as_inner().fd().tell() + self.as_inner().as_inner().tell() } fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> { - self.as_inner().fd().set_flags(flags) + self.as_inner().as_inner().set_flags(flags) } fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> { - self.as_inner().fd().set_rights(rights, inheriting) + self.as_inner().as_inner().set_rights(rights, inheriting) } fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { - self.as_inner().fd().advise(offset, len, advice) + self.as_inner().as_inner().advise(offset, len, advice) } fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - self.as_inner().fd().allocate(offset, len) + self.as_inner().as_inner().allocate(offset, len) } fn create_directory>(&self, dir: P) -> io::Result<()> { - self.as_inner().fd().create_directory(osstr2str(dir.as_ref().as_ref())?) + self.as_inner().as_inner().create_directory(osstr2str(dir.as_ref().as_ref())?) } fn read_link>(&self, path: P) -> io::Result { @@ -269,11 +269,11 @@ impl FileExt for fs::File { } fn remove_file>(&self, path: P) -> io::Result<()> { - self.as_inner().fd().unlink_file(osstr2str(path.as_ref().as_ref())?) + self.as_inner().as_inner().unlink_file(osstr2str(path.as_ref().as_ref())?) } fn remove_directory>(&self, path: P) -> io::Result<()> { - self.as_inner().fd().remove_directory(osstr2str(path.as_ref().as_ref())?) + self.as_inner().as_inner().remove_directory(osstr2str(path.as_ref().as_ref())?) } } @@ -486,10 +486,10 @@ pub fn link, U: AsRef>( new_fd: &File, new_path: U, ) -> io::Result<()> { - old_fd.as_inner().fd().link( + old_fd.as_inner().as_inner().link( old_flags, osstr2str(old_path.as_ref().as_ref())?, - new_fd.as_inner().fd(), + new_fd.as_inner().as_inner(), osstr2str(new_path.as_ref().as_ref())?, ) } @@ -503,9 +503,9 @@ pub fn rename, U: AsRef>( new_fd: &File, new_path: U, ) -> io::Result<()> { - old_fd.as_inner().fd().rename( + old_fd.as_inner().as_inner().rename( osstr2str(old_path.as_ref().as_ref())?, - new_fd.as_inner().fd(), + new_fd.as_inner().as_inner(), osstr2str(new_path.as_ref().as_ref())?, ) } @@ -519,7 +519,7 @@ pub fn symlink, U: AsRef>( new_path: U, ) -> io::Result<()> { fd.as_inner() - .fd() + .as_inner() .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?) } diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs new file mode 100644 index 0000000000000..494903d941c78 --- /dev/null +++ b/library/std/src/os/wasi/io/fd.rs @@ -0,0 +1,280 @@ +//! Owned and borrowed file descriptors. + +#![unstable(feature = "wasi_ext", issue = "71213")] + +use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::fmt; +use crate::fs; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::os::raw; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// A borrowed file descriptor. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the file descriptor. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as an argument, it is not captured or consumed, and it never has the +/// value `-1`. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct BorrowedFd<'fd> { + raw: RawFd, + _phantom: PhantomData<&'fd OwnedFd>, +} + +/// An owned file descriptor. +/// +/// This closes the file descriptor on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as a consumed argument or returned as an owned value, and it never +/// has the value `-1`. +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OwnedFd { + raw: RawFd, +} + +impl BorrowedFd<'_> { + /// Return a `BorrowedFd` holding the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must remain open for the duration of + /// the returned `BorrowedFd`, and it must not have the value `-1`. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub unsafe fn borrow_raw_fd(raw: RawFd) -> Self { + assert_ne!(raw, -1_i32 as RawFd); + unsafe { Self { raw, _phantom: PhantomData } } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsRawFd for BorrowedFd<'_> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.raw + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsRawFd for OwnedFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.raw + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl IntoRawFd for OwnedFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + let raw = self.raw; + forget(self); + raw + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl FromRawFd for OwnedFd { + /// Constructs a new instance of `Self` from the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be open and suitable for assuming + /// ownership. + #[inline] + unsafe fn from_raw_fd(raw: RawFd) -> Self { + assert_ne!(raw, RawFd::MAX); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { Self { raw } } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl Drop for OwnedFd { + #[inline] + fn drop(&mut self) { + unsafe { + // Note that errors are ignored when closing a file descriptor. The + // reason for this is that if an error occurs we don't actually know if + // the file descriptor was closed or not, and if we retried (for + // something like EINTR), we might close another valid file descriptor + // opened after we closed ours. + let _ = libc::close(self.raw as raw::c_int); + } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Debug for BorrowedFd<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedFd").field("fd", &self.raw).finish() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Debug for OwnedFd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedFd").field("fd", &self.raw).finish() + } +} + +/// A trait to borrow the file descriptor from an underlying object. +/// +/// This is only available on unix platforms and must be imported in order to +/// call the method. Windows platforms have a corresponding `AsHandle` and +/// `AsSocket` set of traits. +#[unstable(feature = "io_safety", issue = "87074")] +pub trait AsFd { + /// Borrows the file descriptor. + /// + /// # Example + /// + /// ```rust,no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::io::{AsFd, BorrowedFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[unstable(feature = "io_safety", issue = "87074")] + fn as_fd(&self) -> BorrowedFd<'_>; +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for BorrowedFd<'_> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + *self + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for OwnedFd { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for fs::File { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(file: fs::File) -> OwnedFd { + file.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for fs::File { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::TcpStream { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { + tcp_stream.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::TcpStream { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::TcpListener { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { + tcp_listener.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::TcpListener { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::UdpSocket { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { + udp_socket.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::UdpSocket { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs new file mode 100644 index 0000000000000..6c884e2eaf471 --- /dev/null +++ b/library/std/src/os/wasi/io/mod.rs @@ -0,0 +1,12 @@ +//! WASI-specific extensions to general I/O primitives. + +#![deny(unsafe_op_in_unsafe_fn)] +#![unstable(feature = "wasi_ext", issue = "71213")] + +mod fd; +mod raw; + +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use fd::*; +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use raw::*; diff --git a/library/std/src/os/wasi/io.rs b/library/std/src/os/wasi/io/raw.rs similarity index 65% rename from library/std/src/os/wasi/io.rs rename to library/std/src/os/wasi/io/raw.rs index b6bc74da8e7b5..3e935e2502e9c 100644 --- a/library/std/src/os/wasi/io.rs +++ b/library/std/src/os/wasi/io/raw.rs @@ -1,6 +1,5 @@ -//! WASI-specific extensions to general I/O primitives +//! Unix-specific extensions to general I/O primitives. -#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "71213")] use crate::fs; @@ -9,6 +8,7 @@ use crate::net; use crate::os::raw; use crate::sys; use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::os::wasi::io::OwnedFd; /// Raw file descriptors. /// @@ -19,14 +19,31 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// assuming that negative file descriptors are invalid. pub type RawFd = raw::c_int; -/// A trait to extract the raw WASI file descriptor from an underlying +/// A trait to extract the raw unix file descriptor from an underlying /// object. +/// +/// This is only available on unix platforms and must be imported in order +/// to call the method. Windows platforms have a corresponding `AsRawHandle` +/// and `AsRawSocket` set of traits. pub trait AsRawFd { /// Extracts the raw file descriptor. /// /// This method does **not** pass ownership of the raw file descriptor /// to the caller. The descriptor is only guaranteed to be valid while /// the original object has not yet been destroyed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::io::{AsRawFd, RawFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// // Note that `raw_fd` is only valid as long as `f` exists. + /// let raw_fd: RawFd = f.as_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` fn as_raw_fd(&self) -> RawFd; } @@ -45,6 +62,21 @@ pub trait FromRawFd { /// descriptor they are wrapping. Usage of this function could /// accidentally allow violating this contract which can cause memory /// unsafety in code that relies on it being true. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// # Ok::<(), io::Error>(()) + /// ``` unsafe fn from_raw_fd(fd: RawFd) -> Self; } @@ -56,24 +88,33 @@ pub trait IntoRawFd { /// This function **transfers ownership** of the underlying file descriptor /// to the caller. Callers are then the unique owners of the file descriptor /// and must close the descriptor once it's no longer needed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::wasi::io::{IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` fn into_raw_fd(self) -> RawFd; } -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl AsRawFd for RawFd { #[inline] fn as_raw_fd(&self) -> RawFd { *self } } -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl IntoRawFd for RawFd { #[inline] fn into_raw_fd(self) -> RawFd { self } } -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] impl FromRawFd for RawFd { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> RawFd { @@ -81,87 +122,22 @@ impl FromRawFd for RawFd { } } -impl AsRawFd for net::TcpStream { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() - } -} - -impl FromRawFd for net::TcpStream { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd)) - } -} - -impl IntoRawFd for net::TcpStream { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -impl AsRawFd for net::TcpListener { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() - } -} - -impl FromRawFd for net::TcpListener { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd)) - } -} - -impl IntoRawFd for net::TcpListener { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -impl AsRawFd for net::UdpSocket { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() - } -} - -impl FromRawFd for net::UdpSocket { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd)) - } -} - -impl IntoRawFd for net::UdpSocket { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - impl AsRawFd for fs::File { #[inline] fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().as_raw() + self.as_inner().as_raw_fd() } } - impl FromRawFd for fs::File { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) + unsafe { fs::File::from(OwnedFd::from_raw_fd(fd)) } } } - impl IntoRawFd for fs::File { #[inline] fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() + self.into_inner().into_inner().into_raw_fd() } } diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs index 44b7c32e95617..1338aa271b33f 100644 --- a/library/std/src/os/wasi/mod.rs +++ b/library/std/src/os/wasi/mod.rs @@ -32,6 +32,7 @@ pub mod ffi; pub mod fs; pub mod io; +pub mod net; /// A prelude for conveniently writing platform-specific code. /// diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs new file mode 100644 index 0000000000000..01b2c1033f7e7 --- /dev/null +++ b/library/std/src/os/wasi/net/mod.rs @@ -0,0 +1,8 @@ +//! WASI-specific networking functionality + +#![unstable(feature = "wasi_ext", issue = "71213")] + +mod raw_fd; + +#[unstable(feature = "wasi_ext", issue = "71213")] +pub use self::raw_fd::*; diff --git a/library/std/src/os/wasi/net/raw_fd.rs b/library/std/src/os/wasi/net/raw_fd.rs new file mode 100644 index 0000000000000..201f4fbce390a --- /dev/null +++ b/library/std/src/os/wasi/net/raw_fd.rs @@ -0,0 +1,45 @@ +use crate::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::{net, sys}; + +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.as_inner().socket().as_raw_fd() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + unsafe { + let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); + net::$t::from_inner(sys::net::$t::from_inner(socket)) + } + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner().into_inner().into_raw_fd() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs new file mode 100644 index 0000000000000..d881a67709d8f --- /dev/null +++ b/library/std/src/os/windows/io/handle.rs @@ -0,0 +1,390 @@ +//! Owned and borrowed OS handles. + +#![unstable(feature = "io_safety", issue = "87074")] + +use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use crate::convert::TryFrom; +use crate::ffi::c_void; +use crate::fmt; +use crate::fs; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::ptr::NonNull; +use crate::sys::c; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// A borrowed handle. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the handle. +/// +/// This uses `repr(transparent)` and has the representation of a host handle, +/// so it can be used in FFI in places where a handle is passed as an argument, +/// it is not captured or consumed, and it is never null. +/// +/// Note that it *may* have the value `INVALID_HANDLE_VALUE`. See [here] for +/// the full story. +/// +/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +#[derive(Copy, Clone)] +#[repr(transparent)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct BorrowedHandle<'handle> { + raw: NonNull, + _phantom: PhantomData<&'handle OwnedHandle>, +} + +/// An owned handle. +/// +/// This closes the handle on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host handle, +/// so it can be used in FFI in places where a handle is passed as a consumed +/// argument or returned as an owned value, and is never null. +/// +/// Note that it *may* have the value `INVALID_HANDLE_VALUE`. See [here] for +/// the full story. For APIs like `CreateFileW` which report errors with +/// `INVALID_HANDLE_VALUE` instead of null, use [`OptionFileHandle`] instead +/// of `Option`. +/// +/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +#[repr(transparent)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OwnedHandle { + raw: NonNull, +} + +/// Similar to `Option`, but intended for use in FFI interfaces +/// where `INVALID_HANDLE_VALUE` is used as the sentry value, and null values +/// are not used at all, such as in the return value of `CreateFileW`. +/// +/// If this holds an owned handle, it closes the handle on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host handle, +/// so it can be used in FFI in places where a non-null handle is passed as a +/// consumed argument or returned as an owned value, or it is +/// `INVALID_HANDLE_VALUE` indicating an error or an otherwise absent value. +/// +#[repr(transparent)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OptionFileHandle { + raw: RawHandle, +} + +// The Windows [`HANDLE`] type may be transferred across and shared between +// thread boundaries (despite containing a `*mut void`, which in general isn't +// `Send` or `Sync`). +// +// [`HANDLE`]: std::os::windows::raw::HANDLE +unsafe impl Send for OwnedHandle {} +unsafe impl Send for OptionFileHandle {} +unsafe impl Send for BorrowedHandle<'_> {} +unsafe impl Sync for OwnedHandle {} +unsafe impl Sync for OptionFileHandle {} +unsafe impl Sync for BorrowedHandle<'_> {} + +impl BorrowedHandle<'_> { + /// Return a `BorrowedHandle` holding the given raw handle. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must remain open for the duration of + /// the returned `BorrowedHandle`, and it must not be null. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub unsafe fn borrow_raw_handle(raw: RawHandle) -> Self { + assert!(!raw.is_null()); + Self { raw: NonNull::new_unchecked(raw), _phantom: PhantomData } + } +} + +impl OptionFileHandle { + /// Return an empty `OptionFileHandle` with no resource. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub const fn none() -> Self { + Self { raw: c::INVALID_HANDLE_VALUE } + } +} + +impl TryFrom for OwnedHandle { + type Error = (); + + #[inline] + fn try_from(option: OptionFileHandle) -> Result { + let raw = option.raw; + forget(option); + if let Some(non_null) = NonNull::new(raw) { + if non_null.as_ptr() != c::INVALID_HANDLE_VALUE { + Ok(Self { raw: non_null }) + } else { + Err(()) + } + } else { + // In theory, we ought to be able to assume that the pointer here + // is never null, change `option.raw` to `NonNull`, and obviate the + // the panic path here. Unfortunately, Win32 documentation doesn't + // explicitly guarantee this anywhere. + // + // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a + // null handle indicates an absent value, which wouldn't work if + // null were a valid handle value, so it seems very unlikely that + // it could ever return null. But who knows? + // + // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + panic!("An `OptionFileHandle` was null!"); + } + } +} + +impl From for OptionFileHandle { + #[inline] + fn from(owned: OwnedHandle) -> Self { + let raw = owned.raw; + forget(owned); + Self { raw: raw.as_ptr() } + } +} + +impl AsRawHandle for BorrowedHandle<'_> { + #[inline] + fn as_raw_handle(&self) -> RawHandle { + self.raw.as_ptr() + } +} + +impl AsRawHandle for OwnedHandle { + #[inline] + fn as_raw_handle(&self) -> RawHandle { + self.raw.as_ptr() + } +} + +impl IntoRawHandle for OwnedHandle { + #[inline] + fn into_raw_handle(self) -> RawHandle { + let raw = self.raw.as_ptr(); + forget(self); + raw + } +} + +impl FromRawHandle for OwnedHandle { + /// Constructs a new instance of `Self` from the given raw handle. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be open and suitable for assuming + /// ownership. + #[inline] + unsafe fn from_raw_handle(raw: RawHandle) -> Self { + assert!(!raw.is_null()); + Self { raw: NonNull::new_unchecked(raw) } + } +} + +impl FromRawHandle for OptionFileHandle { + /// Constructs a new instance of `Self` from the given raw handle. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be either open and otherwise + /// unowned, or equal to `INVALID_HANDLE_VALUE``. Note that not all Windows + /// APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for the full + /// story. + /// + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + #[inline] + unsafe fn from_raw_handle(raw: RawHandle) -> Self { + assert!(!raw.is_null()); + Self { raw } + } +} + +impl Drop for OwnedHandle { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::CloseHandle(self.raw.as_ptr()); + } + } +} + +impl Drop for OptionFileHandle { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::CloseHandle(self.raw); + } + } +} + +impl fmt::Debug for BorrowedHandle<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedHandle").field("handle", &self.raw).finish() + } +} + +impl fmt::Debug for OwnedHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedHandle").field("handle", &self.raw).finish() + } +} + +impl fmt::Debug for OptionFileHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OptionFileHandle").field("handle", &self.raw).finish() + } +} + +/// A trait to borrow the handle from an underlying object. +#[unstable(feature = "io_safety", issue = "87074")] +pub trait AsHandle { + /// Borrows the handle. + /// + /// # Example + /// + /// ```rust,no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::windows::{AsHandle, BorrowedHandle}; + /// + /// let mut f = File::open("foo.txt")?; + /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle(); + /// # Ok::<(), io::Error>(()) + /// ``` + fn as_handle(&self) -> BorrowedHandle<'_>; +} + +impl AsHandle for BorrowedHandle<'_> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + *self + } +} + +impl AsHandle for OwnedHandle { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for fs::File { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().as_handle() + } +} + +impl From for OwnedHandle { + #[inline] + fn from(file: fs::File) -> OwnedHandle { + file.into_inner().into_inner().into_inner().into() + } +} + +impl From for fs::File { + #[inline] + fn from(owned: OwnedHandle) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) + } +} + +impl AsHandle for crate::io::Stdin { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl<'a> AsHandle for crate::io::StdinLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for crate::io::Stdout { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl<'a> AsHandle for crate::io::StdoutLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for crate::io::Stderr { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl<'a> AsHandle for crate::io::StderrLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandle for crate::process::ChildStdin { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From for OwnedHandle { + #[inline] + fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) } + } +} + +impl AsHandle for crate::process::ChildStdout { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From for OwnedHandle { + #[inline] + fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) } + } +} + +impl AsHandle for crate::process::ChildStderr { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From for OwnedHandle { + #[inline] + fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) } + } +} + +impl AsHandle for crate::thread::JoinHandle { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + } +} + +impl From> for OwnedHandle { + #[inline] + fn from(join_handle: crate::thread::JoinHandle) -> OwnedHandle { + join_handle.into_inner().into_handle().into_inner() + } +} diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs new file mode 100644 index 0000000000000..d8e453bc0e040 --- /dev/null +++ b/library/std/src/os/windows/io/mod.rs @@ -0,0 +1,56 @@ +//! Windows-specific extensions to general I/O primitives. +//! +//! Just like raw pointers, raw Windows handles and sockets point to resources +//! with dynamic lifetimes, and they can dangle if they outlive their resources +//! or be forged if they're created from invalid values. +//! +//! This module provides three types for representing raw handles and sockets +//! with different ownership properties: raw, borrowed, and owned, which are +//! analogous to types used for representing pointers: +//! +//! | Type | Analogous to | +//! | ---------------------- | ------------ | +//! | [`RawHandle`] | `*const _` | +//! | [`RawSocket`] | `*const _` | +//! | | | +//! | [`BorrowedHandle<'a>`] | `&'a _` | +//! | [`BorrowedSocket<'a>`] | `&'a _` | +//! | | | +//! | [`OwnedHandle`] | `Box<_>` | +//! | [`OwnedSocket`] | `Box<_>` | +//! +//! Like raw pointers, `RawHandle` and `RawSocket` values are primitive values. +//! And in new code, they should be considered unsafe to do I/O on (analogous +//! to dereferencing them). Rust did not always provide this guidance, so +//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and +//! `RawSocket` usage as unsafe. Libraries are encouraged to migrate, either by +//! adding `unsafe` to APIs that dereference `RawHandle` and `RawSocket` +//! values, or by using to `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, +//! or `OwnedSocket`. +//! +//! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a +//! lifetime, to ensure that they don't outlive the resource they point to. +//! These are safe to use. `BorrowedHandle` and `BorrowedSocket` values may be +//! used in APIs which provide safe access to any system call except for +//! `CloseHandle`, `closesocket`, or any other call that would end the +//! dynamic lifetime of the resource without ending the lifetime of the +//! handle or socket. +//! +//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the +//! resource they point to, and free (close) it when they are dropped. +//! +//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle +//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket + +#![stable(feature = "rust1", since = "1.0.0")] + +mod handle; +mod raw; +mod socket; + +#[unstable(feature = "io_safety", issue = "87074")] +pub use handle::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::*; +#[unstable(feature = "io_safety", issue = "87074")] +pub use socket::*; diff --git a/library/std/src/os/windows/io.rs b/library/std/src/os/windows/io/raw.rs similarity index 88% rename from library/std/src/os/windows/io.rs rename to library/std/src/os/windows/io/raw.rs index 31b5d015ed0c3..c7f122048a198 100644 --- a/library/std/src/os/windows/io.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -5,6 +5,7 @@ use crate::fs; use crate::io; use crate::net; +use crate::os::windows::io::{OwnedHandle, OwnedSocket}; use crate::os::windows::raw; use crate::sys; use crate::sys::c; @@ -61,7 +62,7 @@ pub trait IntoRawHandle { impl AsRawHandle for fs::File { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as RawHandle + self.as_inner().as_raw_handle() as RawHandle } } @@ -112,7 +113,9 @@ impl FromRawHandle for fs::File { #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { let handle = handle as c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(handle)) + fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) } } @@ -120,7 +123,7 @@ impl FromRawHandle for fs::File { impl IntoRawHandle for fs::File { #[inline] fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_raw_handle() as *mut _ } } @@ -166,21 +169,21 @@ pub trait IntoRawSocket { impl AsRawSocket for net::TcpStream { #[inline] fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_socket() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpListener { #[inline] fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_socket() } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::UdpSocket { #[inline] fn as_raw_socket(&self) -> RawSocket { - *self.as_inner().socket().as_inner() + self.as_inner().socket().as_raw_socket() } } @@ -188,7 +191,7 @@ impl AsRawSocket for net::UdpSocket { impl FromRawSocket for net::TcpStream { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { - let sock = sys::net::Socket::from_inner(sock); + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) } } @@ -196,7 +199,7 @@ impl FromRawSocket for net::TcpStream { impl FromRawSocket for net::TcpListener { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { - let sock = sys::net::Socket::from_inner(sock); + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) } } @@ -204,7 +207,7 @@ impl FromRawSocket for net::TcpListener { impl FromRawSocket for net::UdpSocket { #[inline] unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { - let sock = sys::net::Socket::from_inner(sock); + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) } } @@ -213,7 +216,7 @@ impl FromRawSocket for net::UdpSocket { impl IntoRawSocket for net::TcpStream { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_raw_socket() } } @@ -221,7 +224,7 @@ impl IntoRawSocket for net::TcpStream { impl IntoRawSocket for net::TcpListener { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_raw_socket() } } @@ -229,6 +232,6 @@ impl IntoRawSocket for net::TcpListener { impl IntoRawSocket for net::UdpSocket { #[inline] fn into_raw_socket(self) -> RawSocket { - self.into_inner().into_socket().into_inner() + self.into_inner().into_socket().into_inner().into_raw_socket() } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs new file mode 100644 index 0000000000000..e45b334690e91 --- /dev/null +++ b/library/std/src/os/windows/io/socket.rs @@ -0,0 +1,212 @@ +//! Owned and borrowed OS sockets. + +#![unstable(feature = "io_safety", issue = "87074")] + +use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; +use crate::fmt; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::sys::c; + +/// A borrowed socket. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the socket. +/// +/// This uses `repr(transparent)` and has the representation of a host socket, +/// so it can be used in FFI in places where a socket is passed as an argument, +/// it is not captured or consumed, and it never has the value +/// `INVALID_SOCKET`. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// This is -2, in two's complement. -1 is `INVALID_SOCKET`. +#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr( + target_pointer_width = "64", + rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) +)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct BorrowedSocket<'socket> { + raw: RawSocket, + _phantom: PhantomData<&'socket OwnedSocket>, +} + +/// An owned socket. +/// +/// This closes the socket on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host socket, +/// so it can be used in FFI in places where a socket is passed as a consumed +/// argument or returned as an owned value, and it never has the value +/// `INVALID_SOCKET`. +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// This is -2, in two's complement. -1 is `INVALID_SOCKET`. +#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr( + target_pointer_width = "64", + rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) +)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OwnedSocket { + raw: RawSocket, +} + +impl BorrowedSocket<'_> { + /// Return a `BorrowedSocket` holding the given raw socket. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must remain open for the duration of + /// the returned `BorrowedSocket`, and it must not have the value + /// `INVALID_SOCKET`. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub unsafe fn borrow_raw_socket(raw: RawSocket) -> Self { + debug_assert_ne!(raw, c::INVALID_SOCKET as RawSocket); + Self { raw, _phantom: PhantomData } + } +} + +impl AsRawSocket for BorrowedSocket<'_> { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.raw + } +} + +impl AsRawSocket for OwnedSocket { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.raw + } +} + +impl IntoRawSocket for OwnedSocket { + #[inline] + fn into_raw_socket(self) -> RawSocket { + let raw = self.raw; + forget(self); + raw + } +} + +impl FromRawSocket for OwnedSocket { + /// Constructs a new instance of `Self` from the given raw socket. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must be open and suitable for assuming + /// ownership. + #[inline] + unsafe fn from_raw_socket(raw: RawSocket) -> Self { + debug_assert_ne!(raw, c::INVALID_SOCKET as RawSocket); + Self { raw } + } +} + +impl Drop for OwnedSocket { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::closesocket(self.raw); + } + } +} + +impl fmt::Debug for BorrowedSocket<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedSocket").field("socket", &self.raw).finish() + } +} + +impl fmt::Debug for OwnedSocket { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedSocket").field("socket", &self.raw).finish() + } +} + +/// A trait to borrow the socket from an underlying object. +#[unstable(feature = "io_safety", issue = "87074")] +pub trait AsSocket { + /// Borrows the socket. + fn as_socket(&self) -> BorrowedSocket<'_>; +} + +impl AsSocket for BorrowedSocket<'_> { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + *self + } +} + +impl AsSocket for OwnedSocket { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl AsSocket for crate::net::TcpStream { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl From for OwnedSocket { + #[inline] + fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) } + } +} + +impl From for crate::net::TcpStream { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} + +impl AsSocket for crate::net::TcpListener { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl From for OwnedSocket { + #[inline] + fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) } + } +} + +impl From for crate::net::TcpListener { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} + +impl AsSocket for crate::net::UdpSocket { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + } +} + +impl From for OwnedSocket { + #[inline] + fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) } + } +} + +impl From for crate::net::UdpSocket { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 9e7ccd015b658..56efb62d649a2 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -12,7 +12,7 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { - let handle = sys::handle::Handle::new(handle as *mut _); + let handle = sys::handle::Handle::from_raw_handle(handle as *mut _); let io = sys::process::Stdio::Handle(handle); process::Stdio::from_inner(io) } @@ -22,14 +22,14 @@ impl FromRawHandle for process::Stdio { impl AsRawHandle for process::Child { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::Child { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } @@ -37,7 +37,7 @@ impl IntoRawHandle for process::Child { impl AsRawHandle for process::ChildStdin { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } @@ -45,7 +45,7 @@ impl AsRawHandle for process::ChildStdin { impl AsRawHandle for process::ChildStdout { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } @@ -53,28 +53,28 @@ impl AsRawHandle for process::ChildStdout { impl AsRawHandle for process::ChildStderr { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdin { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdout { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStderr { fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs index 6bd02054f7150..fb1bf66ceed35 100644 --- a/library/std/src/os/windows/thread.rs +++ b/library/std/src/os/windows/thread.rs @@ -10,7 +10,7 @@ use crate::thread; impl AsRawHandle for thread::JoinHandle { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle().raw() as *mut _ + self.as_inner().handle().as_raw_handle() as *mut _ } } @@ -18,6 +18,6 @@ impl AsRawHandle for thread::JoinHandle { impl IntoRawHandle for thread::JoinHandle { #[inline] fn into_raw_handle(self) -> RawHandle { - self.into_inner().into_handle().into_raw() as *mut _ + self.into_inner().into_handle().into_raw_handle() as *mut _ } } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 28e32681e15b3..0956726084e02 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -5,21 +5,14 @@ mod tests; use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; -use crate::mem; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::cvt; -use crate::sys_common::AsInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use libc::{c_int, c_void}; #[derive(Debug)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] -pub struct FileDesc { - fd: c_int, -} +pub struct FileDesc(OwnedFd); // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, // with the man page quoting that if the count of bytes to read is @@ -67,26 +60,13 @@ const fn max_iov() -> usize { } impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { - assert_ne!(fd, -1i32); - // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { FileDesc { fd } } - } - - pub fn raw(&self) -> c_int { - self.fd - } - - /// Extracts the actual file descriptor without closing it. - pub fn into_raw(self) -> c_int { - let fd = self.fd; - mem::forget(self); - fd - } - pub fn read(&self, buf: &mut [u8]) -> io::Result { let ret = cvt(unsafe { - libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) + libc::read( + self.as_raw_fd(), + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), READ_LIMIT), + ) })?; Ok(ret as usize) } @@ -95,7 +75,7 @@ impl FileDesc { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let ret = cvt(unsafe { libc::readv( - self.fd, + self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, cmp::min(bufs.len(), max_iov()) as c_int, ) @@ -138,7 +118,7 @@ impl FileDesc { unsafe { cvt_pread64( - self.fd, + self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT), offset as i64, @@ -149,7 +129,11 @@ impl FileDesc { pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { - libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) + libc::write( + self.as_raw_fd(), + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), READ_LIMIT), + ) })?; Ok(ret as usize) } @@ -158,7 +142,7 @@ impl FileDesc { pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { let ret = cvt(unsafe { libc::writev( - self.fd, + self.as_raw_fd(), bufs.as_ptr() as *const libc::iovec, cmp::min(bufs.len(), max_iov()) as c_int, ) @@ -196,7 +180,7 @@ impl FileDesc { unsafe { cvt_pwrite64( - self.fd, + self.as_raw_fd(), buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT), offset as i64, @@ -207,7 +191,7 @@ impl FileDesc { #[cfg(target_os = "linux")] pub fn get_cloexec(&self) -> io::Result { - unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } + unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } } #[cfg(not(any( @@ -224,7 +208,7 @@ impl FileDesc { )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { - cvt(libc::ioctl(self.fd, libc::FIOCLEX))?; + cvt(libc::ioctl(self.as_raw_fd(), libc::FIOCLEX))?; Ok(()) } } @@ -242,10 +226,10 @@ impl FileDesc { ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; + let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))?; let new = previous | libc::FD_CLOEXEC; if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?; + cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFD, new))?; } Ok(()) } @@ -261,7 +245,7 @@ impl FileDesc { pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { unsafe { let v = nonblocking as c_int; - cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; + cvt(libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &v))?; Ok(()) } } @@ -269,14 +253,14 @@ impl FileDesc { #[cfg(not(target_os = "linux"))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; + let previous = cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFL))?; let new = if nonblocking { previous | libc::O_NONBLOCK } else { previous & !libc::O_NONBLOCK }; if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; + cvt(libc::fcntl(self.as_raw_fd(), libc::F_SETFL, new))?; } Ok(()) } @@ -296,8 +280,8 @@ impl FileDesc { #[cfg(target_os = "espidf")] let cmd = libc::F_DUPFD; - let fd = cvt(unsafe { libc::fcntl(self.raw(), cmd, 0) })?; - Ok(FileDesc::new(fd)) + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + Ok(unsafe { FileDesc::from_raw_fd(fd) }) } } @@ -312,19 +296,44 @@ impl<'a> Read for &'a FileDesc { } } -impl AsInner for FileDesc { - fn as_inner(&self) -> &c_int { - &self.fd +impl AsInner for FileDesc { + fn as_inner(&self) -> &OwnedFd { + &self.0 + } +} + +impl IntoInner for FileDesc { + fn into_inner(self) -> OwnedFd { + self.0 + } +} + +impl FromInner for FileDesc { + fn from_inner(owned_fd: OwnedFd) -> Self { + Self(owned_fd) + } +} + +impl AsFd for FileDesc { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for FileDesc { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for FileDesc { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() } } -impl Drop for FileDesc { - fn drop(&mut self) { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // opened after we closed ours. - let _ = unsafe { libc::close(self.fd) }; +impl FromRawFd for FileDesc { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) } } diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs index c9520485c3c7c..5d17e46786c79 100644 --- a/library/std/src/sys/unix/fd/tests.rs +++ b/library/std/src/sys/unix/fd/tests.rs @@ -1,9 +1,10 @@ use super::{FileDesc, IoSlice}; +use crate::os::unix::io::FromRawFd; use core::mem::ManuallyDrop; #[test] fn limit_vector_count() { - let stdout = ManuallyDrop::new(unsafe { FileDesc { fd: 1 } }); + let stdout = ManuallyDrop::new(unsafe { FileDesc::from_raw_fd(1) }); let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); assert!(stdout.write_vectored(&bufs).is_ok()); } diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index fd4defd72eb47..6075eb5c7c58a 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -4,13 +4,14 @@ use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Arc; use crate::sys::fd::FileDesc; use crate::sys::time::SystemTime; use crate::sys::{cvt, cvt_r}; -use crate::sys_common::{AsInner, FromInner}; +use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[cfg(any( all(target_os = "linux", target_env = "gnu"), @@ -764,11 +765,11 @@ impl File { // However, since this is a variadic function, C integer promotion rules mean that on // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms). let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; - Ok(File(FileDesc::new(fd))) + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) } pub fn file_attr(&self) -> io::Result { - let fd = self.0.raw(); + let fd = self.as_raw_fd(); cfg_has_statx! { if let Some(ret) = unsafe { try_statx( @@ -787,7 +788,7 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_fsync(self.0.raw()) })?; + cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?; return Ok(()); #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -801,7 +802,7 @@ impl File { } pub fn datasync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; + cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?; return Ok(()); #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -834,14 +835,14 @@ impl File { pub fn truncate(&self, size: u64) -> io::Result<()> { #[cfg(target_os = "android")] - return crate::sys::android::ftruncate64(self.0.raw(), size); + return crate::sys::android::ftruncate64(self.as_raw_fd(), size); #[cfg(not(target_os = "android"))] { use crate::convert::TryInto; let size: off64_t = size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; - cvt_r(|| unsafe { ftruncate64(self.0.raw(), size) }).map(drop) + cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop) } } @@ -891,7 +892,7 @@ impl File { SeekFrom::End(off) => (libc::SEEK_END, off), SeekFrom::Current(off) => (libc::SEEK_CUR, off), }; - let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?; + let n = cvt(unsafe { lseek64(self.as_raw_fd(), pos, whence) })?; Ok(n as u64) } @@ -899,16 +900,8 @@ impl File { self.0.duplicate().map(File) } - pub fn fd(&self) -> &FileDesc { - &self.0 - } - - pub fn into_fd(self) -> FileDesc { - self.0 - } - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; + cvt_r(|| unsafe { libc::fchmod(self.as_raw_fd(), perm.mode) })?; Ok(()) } } @@ -933,9 +926,51 @@ fn cstr(path: &Path) -> io::Result { Ok(CString::new(path.as_os_str().as_bytes())?) } -impl FromInner for File { - fn from_inner(fd: c_int) -> File { - File(FileDesc::new(fd)) +impl AsInner for File { + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl AsInnerMut for File { + fn as_inner_mut(&mut self) -> &mut FileDesc { + &mut self.0 + } +} + +impl IntoInner for File { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for File { + fn from_inner(file_desc: FileDesc) -> Self { + Self(file_desc) + } +} + +impl AsFd for File { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for File { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for File { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for File { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) } } @@ -1009,7 +1044,7 @@ impl fmt::Debug for File { None } - let fd = self.0.raw(); + let fd = self.as_raw_fd(); let mut b = f.debug_struct("File"); b.field("fd", &fd); if let Some(path) = get_path(fd) { diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 3f614fde08aca..c2f5da1dbbb11 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -3,6 +3,7 @@ use crate::ffi::CStr; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::str; use crate::sys::fd::FileDesc; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; @@ -74,10 +75,10 @@ impl Socket { // flag to atomically create the socket and set it as // CLOEXEC. On Linux this was added in 2.6.27. let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?; - Ok(Socket(FileDesc::new(fd))) + Ok(Socket(FileDesc::from_raw_fd(fd))) } else { let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); + let fd = FileDesc::from_raw_fd(fd); fd.set_cloexec()?; let socket = Socket(fd); @@ -109,11 +110,11 @@ impl Socket { ))] { // Like above, set cloexec atomically cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?; - Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))) + Ok((Socket(FileDesc::from_raw_fd(fds[0])), Socket(FileDesc::from_raw_fd(fds[1])))) } else { cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; - let a = FileDesc::new(fds[0]); - let b = FileDesc::new(fds[1]); + let a = FileDesc::from_raw_fd(fds[0]); + let b = FileDesc::from_raw_fd(fds[1]); a.set_cloexec()?; b.set_cloexec()?; Ok((Socket(a), Socket(b))) @@ -131,7 +132,7 @@ impl Socket { self.set_nonblocking(true)?; let r = unsafe { let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) + cvt(libc::connect(self.as_raw_fd(), addrp, len)) }; self.set_nonblocking(false)?; @@ -142,7 +143,7 @@ impl Socket { Err(e) => return Err(e), } - let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 }; + let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { return Err(io::Error::new_const( @@ -212,15 +213,17 @@ impl Socket { target_os = "netbsd", target_os = "openbsd", ))] { - let fd = cvt_r(|| unsafe { - libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) - })?; - Ok(Socket(FileDesc::new(fd))) + unsafe { + let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?; + Ok(Socket(FileDesc::from_raw_fd(fd))) + } } else { - let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) + unsafe { + let fd = cvt_r(|| libc::accept(self.as_raw_fd(), storage, len))?; + let fd = FileDesc::from_raw_fd(fd); + fd.set_cloexec()?; + Ok(Socket(fd)) + } } } } @@ -231,7 +234,7 @@ impl Socket { fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { let ret = cvt(unsafe { - libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) })?; Ok(ret as usize) } @@ -263,7 +266,7 @@ impl Socket { let n = cvt(unsafe { libc::recvfrom( - self.0.raw(), + self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags, @@ -288,7 +291,7 @@ impl Socket { target_os = "openbsd", ))] pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { - let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; + let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?; Ok(n as usize) } @@ -319,7 +322,7 @@ impl Socket { target_os = "openbsd", ))] pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { - let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; + let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?; Ok(n as usize) } @@ -369,7 +372,7 @@ impl Socket { Shutdown::Read => libc::SHUT_RD, Shutdown::Both => libc::SHUT_RDWR, }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; + cvt(unsafe { libc::shutdown(self.as_raw_fd(), how) })?; Ok(()) } @@ -396,7 +399,7 @@ impl Socket { #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop) + cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop) } #[cfg(any(target_os = "solaris", target_os = "illumos"))] @@ -410,23 +413,52 @@ impl Socket { let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } + + // This is used by sys_common code to abstract over Windows and Unix. + pub fn as_raw(&self) -> RawFd { + self.as_raw_fd() + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &FileDesc { + &self.0 + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> FileDesc { + self.0 + } +} + +impl FromInner for Socket { + fn from_inner(file_desc: FileDesc) -> Self { + Self(file_desc) + } +} + +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } } -impl AsInner for Socket { - fn as_inner(&self) -> &c_int { - self.0.as_inner() +impl AsRawFd for Socket { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() } } -impl FromInner for Socket { - fn from_inner(fd: c_int) -> Socket { - Socket(FileDesc::new(fd)) +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() } } -impl IntoInner for Socket { - fn into_inner(self) -> c_int { - self.0.into_raw() +impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) } } diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index 7ae37bdda70bd..a56c275c94207 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -1,7 +1,9 @@ use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; use crate::sys::{cvt, cvt_r}; +use crate::sys_common::IntoInner; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -24,16 +26,20 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { target_os = "openbsd", target_os = "redox" ))] { - cvt(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) })?; - Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1])))) + unsafe { + cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?; + Ok((AnonPipe(FileDesc::from_raw_fd(fds[0])), AnonPipe(FileDesc::from_raw_fd(fds[1])))) + } } else { - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) + unsafe { + cvt(libc::pipe(fds.as_mut_ptr()))?; + + let fd0 = FileDesc::from_raw_fd(fds[0]); + let fd1 = FileDesc::from_raw_fd(fds[1]); + fd0.set_cloexec()?; + fd1.set_cloexec()?; + Ok((AnonPipe(fd0), AnonPipe(fd1))) + } } } } @@ -64,11 +70,10 @@ impl AnonPipe { pub fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() } +} - pub fn fd(&self) -> &FileDesc { - &self.0 - } - pub fn into_fd(self) -> FileDesc { +impl IntoInner for AnonPipe { + fn into_inner(self) -> FileDesc { self.0 } } @@ -76,15 +81,15 @@ impl AnonPipe { pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { // Set both pipes into nonblocking mode as we're gonna be reading from both // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); + let p1 = p1.into_inner(); + let p2 = p2.into_inner(); p1.set_nonblocking(true)?; p2.set_nonblocking(true)?; let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.raw(); + fds[0].fd = p1.as_raw_fd(); fds[0].events = libc::POLLIN; - fds[1].fd = p2.raw(); + fds[1].fd = p2.as_raw_fd(); fds[1].events = libc::POLLIN; loop { // wait for either pipe to become readable using `poll` @@ -120,3 +125,27 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> } } } + +impl AsRawFd for AnonPipe { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl AsFd for AnonPipe { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl IntoRawFd for AnonPipe { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for AnonPipe { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) + } +} diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index a1972380a9fdb..7b261a302c33f 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -13,6 +13,7 @@ use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; use crate::sys_common::process::{CommandEnv, CommandEnvs}; +use crate::sys_common::IntoInner; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -388,17 +389,17 @@ impl Stdio { // stderr. No matter which we dup first, the second will get // overwritten prematurely. Stdio::Fd(ref fd) => { - if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { + if fd.as_raw_fd() >= 0 && fd.as_raw_fd() <= libc::STDERR_FILENO { Ok((ChildStdio::Owned(fd.duplicate()?), None)) } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) + Ok((ChildStdio::Explicit(fd.as_raw_fd()), None)) } } Stdio::MakePipe => { let (reader, writer) = pipe::anon_pipe()?; let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) + Ok((ChildStdio::Owned(theirs.into_inner()), Some(ours))) } #[cfg(not(target_os = "fuchsia"))] @@ -408,7 +409,7 @@ impl Stdio { opts.write(!readable); let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) }; let fd = File::open_c(&path, &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) + Ok((ChildStdio::Owned(fd.into_inner()), None)) } #[cfg(target_os = "fuchsia")] @@ -419,13 +420,13 @@ impl Stdio { impl From for Stdio { fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_fd()) + Stdio::Fd(pipe.into_inner()) } } impl From for Stdio { fn from(file: File) -> Stdio { - Stdio::Fd(file.into_fd()) + Stdio::Fd(file.into_inner()) } } @@ -434,7 +435,7 @@ impl ChildStdio { match *self { ChildStdio::Inherit => None, ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), + ChildStdio::Owned(ref fd) => Some(fd.as_raw_fd()), #[cfg(target_os = "fuchsia")] ChildStdio::Null => None, diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index a05fe8165cff2..b359987595d30 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -1,5 +1,6 @@ use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; +use crate::os::unix::io::{AsFd, BorrowedFd, FromRawFd}; use crate::sys::fd::FileDesc; pub struct Stdin(()); @@ -14,11 +15,11 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read(buf) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) } } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) } } #[inline] @@ -35,11 +36,13 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write(buf) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write(buf) } } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs) + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write_vectored(bufs) + } } #[inline] @@ -60,11 +63,13 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write(buf) + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write(buf) } } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs) + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write_vectored(bufs) + } } #[inline] @@ -86,3 +91,51 @@ pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; pub fn panic_output() -> Option { Some(Stderr::new()) } + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for io::Stdin { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl<'a> AsFd for io::StdinLock<'a> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for io::Stdout { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl<'a> AsFd for io::StdoutLock<'a> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for io::Stderr { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl<'a> AsFd for io::StderrLock<'a> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + } +} diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 1f6ea8d6e8df3..461afd2316f6f 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -6,10 +6,12 @@ use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; use crate::os::raw::c_int; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[derive(Debug)] pub struct WasiFd { - fd: c_int, + fd: OwnedFd, } fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { @@ -27,38 +29,24 @@ fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { } impl WasiFd { - pub unsafe fn from_raw(fd: c_int) -> WasiFd { - WasiFd { fd } - } - - pub fn into_raw(self) -> c_int { - let ret = self.fd; - mem::forget(self); - ret - } - - pub fn as_raw(&self) -> c_int { - self.fd - } - pub fn datasync(&self) -> io::Result<()> { - unsafe { wasi::fd_datasync(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_datasync(self.as_raw_fd()).map_err(err2io) } } pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - unsafe { wasi::fd_pread(self.fd as wasi::Fd, iovec(bufs), offset).map_err(err2io) } + unsafe { wasi::fd_pread(self.as_raw_fd(), iovec(bufs), offset).map_err(err2io) } } pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - unsafe { wasi::fd_pwrite(self.fd as wasi::Fd, ciovec(bufs), offset).map_err(err2io) } + unsafe { wasi::fd_pwrite(self.as_raw_fd(), ciovec(bufs), offset).map_err(err2io) } } pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - unsafe { wasi::fd_read(self.fd as wasi::Fd, iovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_read(self.as_raw_fd(), iovec(bufs)).map_err(err2io) } } pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { wasi::fd_write(self.fd as wasi::Fd, ciovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_write(self.as_raw_fd(), ciovec(bufs)).map_err(err2io) } } pub fn seek(&self, pos: SeekFrom) -> io::Result { @@ -67,37 +55,37 @@ impl WasiFd { SeekFrom::End(pos) => (wasi::WHENCE_END, pos), SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos), }; - unsafe { wasi::fd_seek(self.fd as wasi::Fd, offset, whence).map_err(err2io) } + unsafe { wasi::fd_seek(self.as_raw_fd(), offset, whence).map_err(err2io) } } pub fn tell(&self) -> io::Result { - unsafe { wasi::fd_tell(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_tell(self.as_raw_fd()).map_err(err2io) } } // FIXME: __wasi_fd_fdstat_get pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_flags(self.fd as wasi::Fd, flags).map_err(err2io) } + unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd(), flags).map_err(err2io) } } pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_rights(self.fd as wasi::Fd, base, inheriting).map_err(err2io) } + unsafe { wasi::fd_fdstat_set_rights(self.as_raw_fd(), base, inheriting).map_err(err2io) } } pub fn sync(&self) -> io::Result<()> { - unsafe { wasi::fd_sync(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_sync(self.as_raw_fd()).map_err(err2io) } } pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { - unsafe { wasi::fd_advise(self.fd as wasi::Fd, offset, len, advice).map_err(err2io) } + unsafe { wasi::fd_advise(self.as_raw_fd(), offset, len, advice).map_err(err2io) } } pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - unsafe { wasi::fd_allocate(self.fd as wasi::Fd, offset, len).map_err(err2io) } + unsafe { wasi::fd_allocate(self.as_raw_fd(), offset, len).map_err(err2io) } } pub fn create_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_create_directory(self.fd as wasi::Fd, path).map_err(err2io) } + unsafe { wasi::path_create_directory(self.as_raw_fd(), path).map_err(err2io) } } pub fn link( @@ -108,14 +96,8 @@ impl WasiFd { new_path: &str, ) -> io::Result<()> { unsafe { - wasi::path_link( - self.fd as wasi::Fd, - old_flags, - old_path, - new_fd.fd as wasi::Fd, - new_path, - ) - .map_err(err2io) + wasi::path_link(self.as_raw_fd(), old_flags, old_path, new_fd.as_raw_fd(), new_path) + .map_err(err2io) } } @@ -130,7 +112,7 @@ impl WasiFd { ) -> io::Result { unsafe { wasi::path_open( - self.fd as wasi::Fd, + self.as_raw_fd(), dirflags, path, oflags, @@ -138,34 +120,32 @@ impl WasiFd { fs_rights_inheriting, fs_flags, ) - .map(|fd| WasiFd::from_raw(fd as c_int)) + .map(|fd| WasiFd::from_raw_fd(fd)) .map_err(err2io) } } pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result { unsafe { - wasi::fd_readdir(self.fd as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie) - .map_err(err2io) + wasi::fd_readdir(self.as_raw_fd(), buf.as_mut_ptr(), buf.len(), cookie).map_err(err2io) } } pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result { unsafe { - wasi::path_readlink(self.fd as wasi::Fd, path, buf.as_mut_ptr(), buf.len()) - .map_err(err2io) + wasi::path_readlink(self.as_raw_fd(), path, buf.as_mut_ptr(), buf.len()).map_err(err2io) } } pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> { unsafe { - wasi::path_rename(self.fd as wasi::Fd, old_path, new_fd.fd as wasi::Fd, new_path) + wasi::path_rename(self.as_raw_fd(), old_path, new_fd.as_raw_fd(), new_path) .map_err(err2io) } } pub fn filestat_get(&self) -> io::Result { - unsafe { wasi::fd_filestat_get(self.fd as wasi::Fd).map_err(err2io) } + unsafe { wasi::fd_filestat_get(self.as_raw_fd()).map_err(err2io) } } pub fn filestat_set_times( @@ -175,12 +155,12 @@ impl WasiFd { fstflags: wasi::Fstflags, ) -> io::Result<()> { unsafe { - wasi::fd_filestat_set_times(self.fd as wasi::Fd, atim, mtim, fstflags).map_err(err2io) + wasi::fd_filestat_set_times(self.as_raw_fd(), atim, mtim, fstflags).map_err(err2io) } } pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { - unsafe { wasi::fd_filestat_set_size(self.fd as wasi::Fd, size).map_err(err2io) } + unsafe { wasi::fd_filestat_set_size(self.as_raw_fd(), size).map_err(err2io) } } pub fn path_filestat_get( @@ -188,7 +168,7 @@ impl WasiFd { flags: wasi::Lookupflags, path: &str, ) -> io::Result { - unsafe { wasi::path_filestat_get(self.fd as wasi::Fd, flags, path).map_err(err2io) } + unsafe { wasi::path_filestat_get(self.as_raw_fd(), flags, path).map_err(err2io) } } pub fn path_filestat_set_times( @@ -200,21 +180,21 @@ impl WasiFd { fstflags: wasi::Fstflags, ) -> io::Result<()> { unsafe { - wasi::path_filestat_set_times(self.fd as wasi::Fd, flags, path, atim, mtim, fstflags) + wasi::path_filestat_set_times(self.as_raw_fd(), flags, path, atim, mtim, fstflags) .map_err(err2io) } } pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> { - unsafe { wasi::path_symlink(old_path, self.fd as wasi::Fd, new_path).map_err(err2io) } + unsafe { wasi::path_symlink(old_path, self.as_raw_fd(), new_path).map_err(err2io) } } pub fn unlink_file(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_unlink_file(self.fd as wasi::Fd, path).map_err(err2io) } + unsafe { wasi::path_unlink_file(self.as_raw_fd(), path).map_err(err2io) } } pub fn remove_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_remove_directory(self.fd as wasi::Fd, path).map_err(err2io) } + unsafe { wasi::path_remove_directory(self.as_raw_fd(), path).map_err(err2io) } } pub fn sock_recv( @@ -222,11 +202,11 @@ impl WasiFd { ri_data: &mut [IoSliceMut<'_>], ri_flags: wasi::Riflags, ) -> io::Result<(usize, wasi::Roflags)> { - unsafe { wasi::sock_recv(self.fd as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io) } + unsafe { wasi::sock_recv(self.as_raw_fd(), iovec(ri_data), ri_flags).map_err(err2io) } } pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result { - unsafe { wasi::sock_send(self.fd as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io) } + unsafe { wasi::sock_send(self.as_raw_fd(), ciovec(si_data), si_flags).map_err(err2io) } } pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -235,14 +215,54 @@ impl WasiFd { Shutdown::Write => wasi::SDFLAGS_WR, Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD, }; - unsafe { wasi::sock_shutdown(self.fd as wasi::Fd, how).map_err(err2io) } + unsafe { wasi::sock_shutdown(self.as_raw_fd(), how).map_err(err2io) } + } +} + +impl AsInner for WasiFd { + fn as_inner(&self) -> &OwnedFd { + &self.fd + } +} + +impl AsInnerMut for WasiFd { + fn as_inner_mut(&mut self) -> &mut OwnedFd { + &mut self.fd + } +} + +impl IntoInner for WasiFd { + fn into_inner(self) -> OwnedFd { + self.fd + } +} + +impl FromInner for WasiFd { + fn from_inner(owned_fd: OwnedFd) -> Self { + Self { fd: owned_fd } + } +} + +impl AsFd for WasiFd { + fn as_fd(&self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} + +impl AsRawFd for WasiFd { + fn as_raw_fd(&self) -> RawFd { + self.fd.as_raw_fd() + } +} + +impl IntoRawFd for WasiFd { + fn into_raw_fd(self) -> RawFd { + self.fd.into_raw_fd() } } -impl Drop for WasiFd { - fn drop(&mut self) { - // FIXME: can we handle the return code here even though we can't on - // unix? - let _ = unsafe { wasi::fd_close(self.fd as wasi::Fd) }; +impl FromRawFd for WasiFd { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } } } } diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 55c9c652a8bbb..984dda8dc0b4e 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -8,12 +8,13 @@ use crate::iter; use crate::mem::{self, ManuallyDrop}; use crate::os::raw::c_int; use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sync::Arc; use crate::sys::time::SystemTime; use crate::sys::unsupported; -use crate::sys_common::FromInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; pub use crate::sys_common::fs::{remove_dir_all, try_exists}; @@ -442,22 +443,50 @@ impl File { unsupported() } - pub fn fd(&self) -> &WasiFd { + pub fn read_link(&self, file: &Path) -> io::Result { + read_link(&self.fd, file) + } +} + +impl AsInner for File { + fn as_inner(&self) -> &WasiFd { &self.fd } +} - pub fn into_fd(self) -> WasiFd { +impl IntoInner for File { + fn into_inner(self) -> WasiFd { self.fd } +} - pub fn read_link(&self, file: &Path) -> io::Result { - read_link(&self.fd, file) +impl FromInner for File { + fn from_inner(fd: WasiFd) -> File { + File { fd } + } +} + +impl AsFd for File { + fn as_fd(&self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} + +impl AsRawFd for File { + fn as_raw_fd(&self) -> RawFd { + self.fd.as_raw_fd() + } +} + +impl IntoRawFd for File { + fn into_raw_fd(self) -> RawFd { + self.fd.into_raw_fd() } } -impl FromInner for File { - fn from_inner(fd: c_int) -> File { - unsafe { File { fd: WasiFd::from_raw(fd) } } +impl FromRawFd for File { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } } } } @@ -474,7 +503,7 @@ impl DirBuilder { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("File").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("File").field("fd", &self.as_raw_fd()).finish() } } @@ -654,7 +683,7 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { let relative = CStr::from_ptr(relative_path).to_bytes().to_vec(); return Ok(( - ManuallyDrop::new(WasiFd::from_raw(fd as c_int)), + ManuallyDrop::new(WasiFd::from_raw_fd(fd as c_int)), PathBuf::from(OsString::from_vec(relative)), )); } diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index 50b7352933e57..1bd33f1e50e32 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -6,12 +6,57 @@ use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::os::raw::c_int; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::unsupported; -use crate::sys_common::FromInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; +pub struct Socket(WasiFd); + pub struct TcpStream { - fd: WasiFd, + inner: Socket, +} + +impl AsInner for Socket { + fn as_inner(&self) -> &WasiFd { + &self.0 + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> WasiFd { + self.0 + } +} + +impl FromInner for Socket { + fn from_inner(inner: WasiFd) -> Socket { + Socket(inner) + } +} + +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for Socket { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } + } } impl TcpStream { @@ -107,29 +152,29 @@ impl TcpStream { unsupported() } - pub fn fd(&self) -> &WasiFd { - &self.fd + pub fn socket(&self) -> &Socket { + &self.inner } - pub fn into_fd(self) -> WasiFd { - self.fd + pub fn into_socket(self) -> Socket { + self.inner } } -impl FromInner for TcpStream { - fn from_inner(fd: c_int) -> TcpStream { - unsafe { TcpStream { fd: WasiFd::from_raw(fd) } } +impl FromInner for TcpStream { + fn from_inner(socket: Socket) -> TcpStream { + TcpStream { inner: socket } } } impl fmt::Debug for TcpStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TcpStream").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("TcpStream").field("fd", &self.inner.as_raw_fd()).finish() } } pub struct TcpListener { - fd: WasiFd, + inner: Socket, } impl TcpListener { @@ -173,29 +218,41 @@ impl TcpListener { unsupported() } - pub fn fd(&self) -> &WasiFd { - &self.fd + pub fn socket(&self) -> &Socket { + &self.inner } - pub fn into_fd(self) -> WasiFd { - self.fd + pub fn into_socket(self) -> Socket { + self.inner } } -impl FromInner for TcpListener { - fn from_inner(fd: c_int) -> TcpListener { - unsafe { TcpListener { fd: WasiFd::from_raw(fd) } } +impl AsInner for TcpListener { + fn as_inner(&self) -> &Socket { + &self.inner + } +} + +impl IntoInner for TcpListener { + fn into_inner(self) -> Socket { + self.inner + } +} + +impl FromInner for TcpListener { + fn from_inner(inner: Socket) -> TcpListener { + TcpListener { inner } } } impl fmt::Debug for TcpListener { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TcpListener").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("TcpListener").field("fd", &self.inner.as_raw_fd()).finish() } } pub struct UdpSocket { - fd: WasiFd, + inner: Socket, } impl UdpSocket { @@ -323,24 +380,36 @@ impl UdpSocket { unsupported() } - pub fn fd(&self) -> &WasiFd { - &self.fd + pub fn socket(&self) -> &Socket { + &self.inner + } + + pub fn into_socket(self) -> Socket { + self.inner } +} + +impl AsInner for UdpSocket { + fn as_inner(&self) -> &Socket { + &self.inner + } +} - pub fn into_fd(self) -> WasiFd { - self.fd +impl IntoInner for UdpSocket { + fn into_inner(self) -> Socket { + self.inner } } -impl FromInner for UdpSocket { - fn from_inner(fd: c_int) -> UdpSocket { - unsafe { UdpSocket { fd: WasiFd::from_raw(fd) } } +impl FromInner for UdpSocket { + fn from_inner(inner: Socket) -> UdpSocket { + UdpSocket { inner } } } impl fmt::Debug for UdpSocket { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("UdpSocket").field("fd", &self.fd.as_raw()).finish() + f.debug_struct("UdpSocket").field("fd", &self.inner.as_raw_fd()).finish() } } diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 8782f333a1fa4..2c8f394cd47b0 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -4,6 +4,7 @@ use super::fd::WasiFd; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::raw; +use crate::os::wasi::io::{AsRawFd, FromRawFd}; pub struct Stdin; pub struct Stdout; @@ -13,9 +14,11 @@ impl Stdin { pub const fn new() -> Stdin { Stdin } +} +impl AsRawFd for Stdin { #[inline] - pub fn as_raw_fd(&self) -> raw::c_int { + fn as_raw_fd(&self) -> raw::c_int { 0 } } @@ -26,7 +29,7 @@ impl io::Read for Stdin { } fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data) + ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).read(data) } #[inline] @@ -39,9 +42,11 @@ impl Stdout { pub const fn new() -> Stdout { Stdout } +} +impl AsRawFd for Stdout { #[inline] - pub fn as_raw_fd(&self) -> raw::c_int { + fn as_raw_fd(&self) -> raw::c_int { 1 } } @@ -52,7 +57,7 @@ impl io::Write for Stdout { } fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) + ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data) } #[inline] @@ -68,9 +73,11 @@ impl Stderr { pub const fn new() -> Stderr { Stderr } +} +impl AsRawFd for Stderr { #[inline] - pub fn as_raw_fd(&self) -> raw::c_int { + fn as_raw_fd(&self) -> raw::c_int { 2 } } @@ -81,7 +88,7 @@ impl io::Write for Stderr { } fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) + ManuallyDrop::new(unsafe { WasiFd::from_raw_fd(self.as_raw_fd()) }).write(data) } #[inline] diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index c677adae6888e..0c1a50e231cd4 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -4,6 +4,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::io::{self, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; +use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::path::{Path, PathBuf}; use crate::ptr; use crate::slice; @@ -11,7 +12,7 @@ use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::time::SystemTime; use crate::sys::{c, cvt}; -use crate::sys_common::FromInner; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use super::to_u16s; @@ -295,12 +296,12 @@ impl File { if handle == c::INVALID_HANDLE_VALUE { Err(Error::last_os_error()) } else { - Ok(File { handle: Handle::new(handle) }) + unsafe { Ok(File { handle: Handle::from_raw_handle(handle) }) } } } pub fn fsync(&self) -> io::Result<()> { - cvt(unsafe { c::FlushFileBuffers(self.handle.raw()) })?; + cvt(unsafe { c::FlushFileBuffers(self.handle.as_raw_handle()) })?; Ok(()) } @@ -313,7 +314,7 @@ impl File { let size = mem::size_of_val(&info); cvt(unsafe { c::SetFileInformationByHandle( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileEndOfFileInfo, &mut info as *mut _ as *mut _, size as c::DWORD, @@ -326,7 +327,7 @@ impl File { pub fn file_attr(&self) -> io::Result { unsafe { let mut info: c::BY_HANDLE_FILE_INFORMATION = mem::zeroed(); - cvt(c::GetFileInformationByHandle(self.handle.raw(), &mut info))?; + cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; @@ -449,7 +450,7 @@ impl File { }; let pos = pos as c::LARGE_INTEGER; let mut newpos = 0; - cvt(unsafe { c::SetFilePointerEx(self.handle.raw(), pos, &mut newpos, whence) })?; + cvt(unsafe { c::SetFilePointerEx(self.handle.as_raw_handle(), pos, &mut newpos, whence) })?; Ok(newpos as u64) } @@ -457,14 +458,6 @@ impl File { Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? }) } - pub fn handle(&self) -> &Handle { - &self.handle - } - - pub fn into_handle(self) -> Handle { - self.handle - } - fn reparse_point<'a>( &self, space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE], @@ -473,7 +466,7 @@ impl File { let mut bytes = 0; cvt({ c::DeviceIoControl( - self.handle.raw(), + self.handle.as_raw_handle(), c::FSCTL_GET_REPARSE_POINT, ptr::null_mut(), 0, @@ -541,7 +534,7 @@ impl File { let size = mem::size_of_val(&info); cvt(unsafe { c::SetFileInformationByHandle( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileBasicInfo, &mut info as *mut _ as *mut _, size as c::DWORD, @@ -551,9 +544,45 @@ impl File { } } -impl FromInner for File { - fn from_inner(handle: c::HANDLE) -> File { - File { handle: Handle::new(handle) } +impl AsInner for File { + fn as_inner(&self) -> &Handle { + &self.handle + } +} + +impl IntoInner for File { + fn into_inner(self) -> Handle { + self.handle + } +} + +impl FromInner for File { + fn from_inner(handle: Handle) -> File { + File { handle: handle } + } +} + +impl AsHandle for File { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().as_handle() + } +} + +impl AsRawHandle for File { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().as_raw_handle() + } +} + +impl IntoRawHandle for File { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_raw_handle() + } +} + +impl FromRawHandle for File { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { + Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } } } @@ -561,7 +590,7 @@ impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(#24570): add more info here (e.g., mode) let mut b = f.debug_struct("File"); - b.field("handle", &self.handle.raw()); + b.field("handle", &self.handle.as_raw_handle()); if let Ok(path) = get_path(&self) { b.field("path", &path); } @@ -838,7 +867,7 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { fn get_path(f: &File) -> io::Result { super::fill_utf16_buf( |buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, c::VOLUME_NAME_DOS) + c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) }, |buf| PathBuf::from(OsString::from_wide(buf)), ) @@ -909,7 +938,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { opts.write(true); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); let f = File::open(junction, &opts)?; - let h = f.handle().raw(); + let h = f.as_inner().as_raw_handle(); unsafe { let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 0d4baa3b340df..21d86b002264a 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -3,76 +3,87 @@ use crate::cmp; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read}; use crate::mem; -use crate::ops::Deref; +use crate::os::windows::io::{ + AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, +}; use crate::ptr; use crate::sys::c; use crate::sys::cvt; +use crate::sys_common::{AsInner, FromInner, IntoInner}; /// An owned container for `HANDLE` object, closing them on Drop. /// /// All methods are inherited through a `Deref` impl to `RawHandle` -pub struct Handle(RawHandle); - -/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference -/// as well as Rust-y methods. -/// -/// This does **not** drop the handle when it goes out of scope, use `Handle` -/// instead for that. -#[derive(Copy, Clone)] -pub struct RawHandle(c::HANDLE); - -unsafe impl Send for RawHandle {} -unsafe impl Sync for RawHandle {} +pub struct Handle(OwnedHandle); impl Handle { - pub fn new(handle: c::HANDLE) -> Handle { - Handle(RawHandle::new(handle)) - } - pub fn new_event(manual: bool, init: bool) -> io::Result { unsafe { let event = c::CreateEventW(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null()); - if event.is_null() { Err(io::Error::last_os_error()) } else { Ok(Handle::new(event)) } + if event.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(Handle::from_raw_handle(event)) + } } } +} - pub fn into_raw(self) -> c::HANDLE { - let ret = self.raw(); - mem::forget(self); - ret +impl AsInner for Handle { + fn as_inner(&self) -> &OwnedHandle { + &self.0 } } -impl Deref for Handle { - type Target = RawHandle; - fn deref(&self) -> &RawHandle { - &self.0 +impl IntoInner for Handle { + fn into_inner(self) -> OwnedHandle { + self.0 } } -impl Drop for Handle { - fn drop(&mut self) { - unsafe { - let _ = c::CloseHandle(self.raw()); - } +impl FromInner for Handle { + fn from_inner(file_desc: OwnedHandle) -> Self { + Self(file_desc) } } -impl RawHandle { - pub fn new(handle: c::HANDLE) -> RawHandle { - RawHandle(handle) +impl AsHandle for Handle { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.0.as_handle() } +} - pub fn raw(&self) -> c::HANDLE { - self.0 +impl AsRawHandle for Handle { + fn as_raw_handle(&self) -> RawHandle { + self.0.as_raw_handle() } +} +impl IntoRawHandle for Handle { + fn into_raw_handle(self) -> RawHandle { + self.0.into_raw_handle() + } +} + +impl FromRawHandle for Handle { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { + Self(FromRawHandle::from_raw_handle(raw_handle)) + } +} + +impl Handle { pub fn read(&self, buf: &mut [u8]) -> io::Result { let mut read = 0; let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; let res = cvt(unsafe { - c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, ptr::null_mut()) + c::ReadFile( + self.as_raw_handle(), + buf.as_mut_ptr() as c::LPVOID, + len, + &mut read, + ptr::null_mut(), + ) }); match res { @@ -104,7 +115,13 @@ impl RawHandle { let mut overlapped: c::OVERLAPPED = mem::zeroed(); overlapped.Offset = offset as u32; overlapped.OffsetHigh = (offset >> 32) as u32; - cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, &mut overlapped)) + cvt(c::ReadFile( + self.as_raw_handle(), + buf.as_mut_ptr() as c::LPVOID, + len, + &mut read, + &mut overlapped, + )) }; match res { Ok(_) => Ok(read as usize), @@ -120,7 +137,13 @@ impl RawHandle { ) -> io::Result> { let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; let mut amt = 0; - let res = cvt(c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped)); + let res = cvt(c::ReadFile( + self.as_raw_handle(), + buf.as_ptr() as c::LPVOID, + len, + &mut amt, + overlapped, + )); match res { Ok(_) => Ok(Some(amt as usize)), Err(e) => { @@ -143,7 +166,8 @@ impl RawHandle { unsafe { let mut bytes = 0; let wait = if wait { c::TRUE } else { c::FALSE }; - let res = cvt(c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait)); + let res = + cvt(c::GetOverlappedResult(self.as_raw_handle(), overlapped, &mut bytes, wait)); match res { Ok(_) => Ok(bytes as usize), Err(e) => { @@ -160,14 +184,20 @@ impl RawHandle { } pub fn cancel_io(&self) -> io::Result<()> { - unsafe { cvt(c::CancelIo(self.raw())).map(drop) } + unsafe { cvt(c::CancelIo(self.as_raw_handle())).map(drop) } } pub fn write(&self, buf: &[u8]) -> io::Result { let mut amt = 0; let len = cmp::min(buf.len(), ::MAX as usize) as c::DWORD; cvt(unsafe { - c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, ptr::null_mut()) + c::WriteFile( + self.as_raw_handle(), + buf.as_ptr() as c::LPVOID, + len, + &mut amt, + ptr::null_mut(), + ) })?; Ok(amt as usize) } @@ -189,7 +219,7 @@ impl RawHandle { overlapped.Offset = offset as u32; overlapped.OffsetHigh = (offset >> 32) as u32; cvt(c::WriteFile( - self.0, + self.as_raw_handle(), buf.as_ptr() as c::LPVOID, len, &mut written, @@ -210,7 +240,7 @@ impl RawHandle { let cur_proc = c::GetCurrentProcess(); c::DuplicateHandle( cur_proc, - self.0, + self.as_raw_handle(), cur_proc, &mut ret, access, @@ -218,11 +248,11 @@ impl RawHandle { options, ) })?; - Ok(Handle::new(ret)) + unsafe { Ok(Handle::from_raw_handle(ret)) } } } -impl<'a> Read for &'a RawHandle { +impl<'a> Read for &'a Handle { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 9cea5c5e63a2d..55aacb38c6f78 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -4,6 +4,9 @@ use crate::cmp; use crate::io::{self, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; +use crate::os::windows::io::{ + AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, +}; use crate::ptr; use crate::sync::Once; use crate::sys; @@ -24,7 +27,7 @@ pub mod netc { pub use crate::sys::c::*; } -pub struct Socket(c::SOCKET); +pub struct Socket(OwnedSocket); static INIT: Once = Once::new(); @@ -109,7 +112,7 @@ impl Socket { }; if socket != c::INVALID_SOCKET { - Ok(Self(socket)) + unsafe { Ok(Self::from_raw_socket(socket)) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -124,9 +127,11 @@ impl Socket { return Err(last_error()); } - let socket = Self(socket); - socket.set_no_inherit()?; - Ok(socket) + unsafe { + let socket = Self::from_raw_socket(socket); + socket.set_no_inherit()?; + Ok(socket) + } } } @@ -134,7 +139,7 @@ impl Socket { self.set_nonblocking(true)?; let result = { let (addrp, len) = addr.into_inner(); - let result = unsafe { c::connect(self.0, addrp, len) }; + let result = unsafe { c::connect(self.as_raw_socket(), addrp, len) }; cvt(result).map(drop) }; self.set_nonblocking(false)?; @@ -160,7 +165,7 @@ impl Socket { let fds = { let mut fds = unsafe { mem::zeroed::() }; fds.fd_count = 1; - fds.fd_array[0] = self.0; + fds.fd_array[0] = self.as_raw_socket(); fds }; @@ -194,17 +199,19 @@ impl Socket { } pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result { - let socket = unsafe { c::accept(self.0, storage, len) }; + let socket = unsafe { c::accept(self.as_raw_socket(), storage, len) }; match socket { c::INVALID_SOCKET => Err(last_error()), - _ => Ok(Self(socket)), + _ => unsafe { Ok(Self::from_raw_socket(socket)) }, } } pub fn duplicate(&self) -> io::Result { let mut info = unsafe { mem::zeroed::() }; - let result = unsafe { c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info) }; + let result = unsafe { + c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) + }; cvt(result)?; let socket = unsafe { c::WSASocketW( @@ -218,7 +225,7 @@ impl Socket { }; if socket != c::INVALID_SOCKET { - Ok(Self(socket)) + unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -241,9 +248,11 @@ impl Socket { return Err(last_error()); } - let socket = Self(socket); - socket.set_no_inherit()?; - Ok(socket) + unsafe { + let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); + socket.set_no_inherit()?; + Ok(socket) + } } } @@ -251,7 +260,8 @@ impl Socket { // On unix when a socket is shut down all further reads return 0, so we // do the same on windows to map a shut down socket to returning EOF. let length = cmp::min(buf.len(), i32::MAX as usize) as i32; - let result = unsafe { c::recv(self.0, buf.as_mut_ptr() as *mut _, length, flags) }; + let result = + unsafe { c::recv(self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags) }; match result { c::SOCKET_ERROR => { @@ -279,7 +289,7 @@ impl Socket { let mut flags = 0; let result = unsafe { c::WSARecv( - self.0, + self.as_raw_socket(), bufs.as_mut_ptr() as *mut c::WSABUF, length, &mut nread, @@ -325,7 +335,7 @@ impl Socket { // do the same on windows to map a shut down socket to returning EOF. let result = unsafe { c::recvfrom( - self.0, + self.as_raw_socket(), buf.as_mut_ptr() as *mut _, length, flags, @@ -361,7 +371,7 @@ impl Socket { let mut nwritten = 0; let result = unsafe { c::WSASend( - self.0, + self.as_raw_socket(), bufs.as_ptr() as *const c::WSABUF as *mut _, length, &mut nwritten, @@ -408,8 +418,10 @@ impl Socket { #[cfg(not(target_vendor = "uwp"))] fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { c::SetHandleInformation(self.0 as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) }) - .map(drop) + sys::cvt(unsafe { + c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) + }) + .map(drop) } #[cfg(target_vendor = "uwp")] @@ -423,13 +435,14 @@ impl Socket { Shutdown::Read => c::SD_RECEIVE, Shutdown::Both => c::SD_BOTH, }; - let result = unsafe { c::shutdown(self.0, how) }; + let result = unsafe { c::shutdown(self.as_raw_socket(), how) }; cvt(result).map(drop) } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as c_ulong; - let result = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) }; + let result = + unsafe { c::ioctlsocket(self.as_raw_socket(), c::FIONBIO as c_int, &mut nonblocking) }; cvt(result).map(drop) } @@ -446,6 +459,11 @@ impl Socket { let raw: c_int = net::getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } + + // This is used by sys_common code to abstract over Windows and Unix. + pub fn as_raw(&self) -> RawSocket { + self.as_inner().as_raw_socket() + } } #[unstable(reason = "not public", issue = "none", feature = "fd_read")] @@ -455,28 +473,44 @@ impl<'a> Read for &'a Socket { } } -impl Drop for Socket { - fn drop(&mut self) { - let _ = unsafe { c::closesocket(self.0) }; +impl AsInner for Socket { + fn as_inner(&self) -> &OwnedSocket { + &self.0 } } -impl AsInner for Socket { - fn as_inner(&self) -> &c::SOCKET { - &self.0 +impl FromInner for Socket { + fn from_inner(sock: OwnedSocket) -> Socket { + Socket(sock) } } -impl FromInner for Socket { - fn from_inner(sock: c::SOCKET) -> Socket { - Socket(sock) +impl IntoInner for Socket { + fn into_inner(self) -> OwnedSocket { + self.0 + } +} + +impl AsSocket for Socket { + fn as_socket(&self) -> BorrowedSocket<'_> { + self.0.as_socket() + } +} + +impl AsRawSocket for Socket { + fn as_raw_socket(&self) -> RawSocket { + self.0.as_raw_socket() + } +} + +impl IntoRawSocket for Socket { + fn into_raw_socket(self) -> RawSocket { + self.0.into_raw_socket() } } -impl IntoInner for Socket { - fn into_inner(self) -> c::SOCKET { - let ret = self.0; - mem::forget(self); - ret +impl FromRawSocket for Socket { + unsafe fn from_raw_socket(raw_socket: RawSocket) -> Self { + Self(FromRawSocket::from_raw_socket(raw_socket)) } } diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index 8db97ba50a81f..883690c483167 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -288,7 +288,7 @@ fn home_dir_crt() -> Option { if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 { return None; } - let _handle = Handle::new(token); + let _handle = Handle::from_raw_handle(token); super::fill_utf16_buf( |buf, mut sz| { match c::GetUserProfileDirectoryW(token, buf, &mut sz) { diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs index 104a8db46596e..63d3d6c5ed42f 100644 --- a/library/std/src/sys/windows/pipe.rs +++ b/library/std/src/sys/windows/pipe.rs @@ -12,6 +12,7 @@ use crate::sys::c; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::hashmap_random_keys; +use crate::sys_common::IntoInner; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -21,6 +22,12 @@ pub struct AnonPipe { inner: Handle, } +impl IntoInner for AnonPipe { + fn into_inner(self) -> Handle { + self.inner + } +} + pub struct Pipes { pub ours: AnonPipe, pub theirs: AnonPipe, @@ -123,7 +130,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res } return Err(err); } - ours = Handle::new(handle); + ours = Handle::from_raw_handle(handle); break; } @@ -146,11 +153,11 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res }; opts.security_attributes(&mut sa); let theirs = File::open(Path::new(&name), &opts)?; - let theirs = AnonPipe { inner: theirs.into_handle() }; + let theirs = AnonPipe { inner: theirs.into_inner() }; Ok(Pipes { ours: AnonPipe { inner: ours }, - theirs: AnonPipe { inner: theirs.into_handle() }, + theirs: AnonPipe { inner: theirs.into_inner() }, }) } } @@ -207,7 +214,7 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> let mut p1 = AsyncPipe::new(p1, v1)?; let mut p2 = AsyncPipe::new(p2, v2)?; - let objs = [p1.event.raw(), p2.event.raw()]; + let objs = [p1.event.as_raw_handle(), p2.event.as_raw_handle()]; // In a loop we wait for either pipe's scheduled read operation to complete. // If the operation completes with 0 bytes, that means EOF was reached, in @@ -262,7 +269,7 @@ impl<'a> AsyncPipe<'a> { // I/O operation is successfully scheduled (what we want). let event = Handle::new_event(true, true)?; let mut overlapped: Box = unsafe { Box::new(mem::zeroed()) }; - overlapped.hEvent = event.raw(); + overlapped.hEvent = event.as_raw_handle(); Ok(AsyncPipe { pipe, overlapped, event, dst, state: State::NotReading }) } diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index ae193b82e91bb..5cfde16faf0b1 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -15,6 +15,7 @@ use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; use crate::os::windows::ffi::OsStrExt; +use crate::os::windows::io::{AsRawHandle, FromRawHandle}; use crate::path::Path; use crate::ptr; use crate::sys::c; @@ -26,7 +27,7 @@ use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; use crate::sys_common::mutex::StaticMutex; use crate::sys_common::process::{CommandEnv, CommandEnvs}; -use crate::sys_common::AsInner; +use crate::sys_common::{AsInner, IntoInner}; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -316,9 +317,9 @@ impl Command { let stdin = stdin.to_handle(c::STD_INPUT_HANDLE, &mut pipes.stdin)?; let stdout = stdout.to_handle(c::STD_OUTPUT_HANDLE, &mut pipes.stdout)?; let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; - si.hStdInput = stdin.raw(); - si.hStdOutput = stdout.raw(); - si.hStdError = stderr.raw(); + si.hStdInput = stdin.as_raw_handle(); + si.hStdOutput = stdout.as_raw_handle(); + si.hStdError = stderr.as_raw_handle(); unsafe { cvt(c::CreateProcessW( @@ -338,9 +339,11 @@ impl Command { // We close the thread handle because we don't care about keeping // the thread id valid, and we aren't keeping the thread handle // around to be able to close it later. - drop(Handle::new(pi.hThread)); + unsafe { + drop(Handle::from_raw_handle(pi.hThread)); - Ok((Process { handle: Handle::new(pi.hProcess) }, pipes)) + Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes)) + } } } @@ -365,13 +368,13 @@ impl Stdio { // should still be unavailable so propagate the // INVALID_HANDLE_VALUE. Stdio::Inherit => match stdio::get_handle(stdio_id) { - Ok(io) => { - let io = Handle::new(io); + Ok(io) => unsafe { + let io = Handle::from_raw_handle(io); let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); - io.into_raw(); + io.into_inner(); ret - } - Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), + }, + Err(..) => unsafe { Ok(Handle::from_raw_handle(c::INVALID_HANDLE_VALUE)) }, }, Stdio::MakePipe => { @@ -397,7 +400,7 @@ impl Stdio { opts.read(stdio_id == c::STD_INPUT_HANDLE); opts.write(stdio_id != c::STD_INPUT_HANDLE); opts.security_attributes(&mut sa); - File::open(Path::new("NUL"), &opts).map(|file| file.into_handle()) + File::open(Path::new("NUL"), &opts).map(|file| file.into_inner()) } } } @@ -411,7 +414,7 @@ impl From for Stdio { impl From for Stdio { fn from(file: File) -> Stdio { - Stdio::Handle(file.into_handle()) + Stdio::Handle(file.into_inner()) } } @@ -430,29 +433,29 @@ pub struct Process { impl Process { pub fn kill(&mut self) -> io::Result<()> { - cvt(unsafe { c::TerminateProcess(self.handle.raw(), 1) })?; + cvt(unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) })?; Ok(()) } pub fn id(&self) -> u32 { - unsafe { c::GetProcessId(self.handle.raw()) as u32 } + unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 } } pub fn wait(&mut self) -> io::Result { unsafe { - let res = c::WaitForSingleObject(self.handle.raw(), c::INFINITE); + let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE); if res != c::WAIT_OBJECT_0 { return Err(Error::last_os_error()); } let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; + cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?; Ok(ExitStatus(status)) } } pub fn try_wait(&mut self) -> io::Result> { unsafe { - match c::WaitForSingleObject(self.handle.raw(), 0) { + match c::WaitForSingleObject(self.handle.as_raw_handle(), 0) { c::WAIT_OBJECT_0 => {} c::WAIT_TIMEOUT => { return Ok(None); @@ -460,7 +463,7 @@ impl Process { _ => return Err(io::Error::last_os_error()), } let mut status = 0; - cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?; + cvt(c::GetExitCodeProcess(self.handle.as_raw_handle(), &mut status))?; Ok(Some(ExitStatus(status))) } } diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index 2973951fe9004..1cf0e9f0cf1ea 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -3,6 +3,7 @@ use crate::char::decode_utf16; use crate::cmp; use crate::io; +use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::ptr; use crate::str; use crate::sys::c; @@ -53,10 +54,12 @@ fn is_console(handle: c::HANDLE) -> bool { fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result { let handle = get_handle(handle_id)?; if !is_console(handle) { - let handle = Handle::new(handle); - let ret = handle.write(data); - handle.into_raw(); // Don't close the handle - return ret; + unsafe { + let handle = Handle::from_raw_handle(handle); + let ret = handle.write(data); + handle.into_raw_handle(); // Don't close the handle + return ret; + } } // As the console is meant for presenting text, we assume bytes of `data` come from a string @@ -140,10 +143,12 @@ impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { let handle = get_handle(c::STD_INPUT_HANDLE)?; if !is_console(handle) { - let handle = Handle::new(handle); - let ret = handle.read(buf); - handle.into_raw(); // Don't close the handle - return ret; + unsafe { + let handle = Handle::from_raw_handle(handle); + let ret = handle.read(buf); + handle.into_raw_handle(); // Don't close the handle + return ret; + } } if buf.len() == 0 { diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index ef7a9733fd880..a5293133b3ab0 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -1,6 +1,7 @@ use crate::ffi::CStr; use crate::io; use crate::num::NonZeroUsize; +use crate::os::windows::io::{AsRawHandle, FromRawHandle}; use crate::ptr; use crate::sys::c; use crate::sys::handle::Handle; @@ -45,7 +46,7 @@ impl Thread { drop(Box::from_raw(p)); Err(io::Error::last_os_error()) } else { - Ok(Thread { handle: Handle::new(ret) }) + Ok(Thread { handle: Handle::from_raw_handle(ret) }) }; extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { @@ -71,7 +72,7 @@ impl Thread { } pub fn join(self) { - let rc = unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE) }; + let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; if rc == c::WAIT_FAILED { panic!("failed to join on thread: {}", io::Error::last_os_error()); } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index d5f29c4a43970..0ffa5c01dd33b 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -61,13 +61,7 @@ cfg_if::cfg_if! { pub fn setsockopt(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> { unsafe { let payload = &payload as *const T as *const c_void; - cvt(c::setsockopt( - *sock.as_inner(), - opt, - val, - payload, - mem::size_of::() as c::socklen_t, - ))?; + cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::() as c::socklen_t))?; Ok(()) } } @@ -76,7 +70,7 @@ pub fn getsockopt(sock: &Socket, opt: c_int, val: c_int) -> io::Result< unsafe { let mut slot: T = mem::zeroed(); let mut len = mem::size_of::() as c::socklen_t; - cvt(c::getsockopt(*sock.as_inner(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?; + cvt(c::getsockopt(sock.as_raw(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?; assert_eq!(len as usize, mem::size_of::()); Ok(slot) } @@ -217,7 +211,7 @@ impl TcpStream { let sock = Socket::new(addr, c::SOCK_STREAM)?; let (addrp, len) = addr.into_inner(); - cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?; + cvt_r(|| unsafe { c::connect(sock.as_raw(), addrp, len) })?; Ok(TcpStream { inner: sock }) } @@ -273,7 +267,7 @@ impl TcpStream { pub fn write(&self, buf: &[u8]) -> io::Result { let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; let ret = cvt(unsafe { - c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) + c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) })?; Ok(ret as usize) } @@ -288,11 +282,11 @@ impl TcpStream { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) } pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -348,7 +342,7 @@ impl fmt::Debug for TcpStream { } let name = if cfg!(windows) { "socket" } else { "fd" }; - res.field(name, &self.inner.as_inner()).finish() + res.field(name, &self.inner.as_raw()).finish() } } @@ -380,10 +374,10 @@ impl TcpListener { // Bind our new socket let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; + cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?; // Start listening - cvt(unsafe { c::listen(*sock.as_inner(), 128) })?; + cvt(unsafe { c::listen(sock.as_raw(), 128) })?; Ok(TcpListener { inner: sock }) } @@ -396,7 +390,7 @@ impl TcpListener { } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { @@ -453,7 +447,7 @@ impl fmt::Debug for TcpListener { } let name = if cfg!(windows) { "socket" } else { "fd" }; - res.field(name, &self.inner.as_inner()).finish() + res.field(name, &self.inner.as_raw()).finish() } } @@ -473,7 +467,7 @@ impl UdpSocket { let sock = Socket::new(addr, c::SOCK_DGRAM)?; let (addrp, len) = addr.into_inner(); - cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?; + cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?; Ok(UdpSocket { inner: sock }) } @@ -486,11 +480,11 @@ impl UdpSocket { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(*self.inner.as_inner(), buf, len) }) + sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { @@ -506,7 +500,7 @@ impl UdpSocket { let (dstp, dstlen) = dst.into_inner(); let ret = cvt(unsafe { c::sendto( - *self.inner.as_inner(), + self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL, @@ -643,14 +637,14 @@ impl UdpSocket { pub fn send(&self, buf: &[u8]) -> io::Result { let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; let ret = cvt(unsafe { - c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) + c::send(self.inner.as_raw(), buf.as_ptr() as *const c_void, len, MSG_NOSIGNAL) })?; Ok(ret as usize) } pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { let (addrp, len) = addr?.into_inner(); - cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(drop) + cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addrp, len) }).map(drop) } } @@ -669,6 +663,6 @@ impl fmt::Debug for UdpSocket { } let name = if cfg!(windows) { "socket" } else { "fd" }; - res.field(name, &self.inner.as_inner()).finish() + res.field(name, &self.inner.as_raw()).finish() } } From 3a38511ab338cdfe5dbec2382b819f4834eeef1d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 21 Jul 2021 10:06:26 -0700 Subject: [PATCH 02/28] Update library/std/src/os/unix/io/fd.rs Co-authored-by: Josh Triplett --- library/std/src/os/unix/io/fd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs index 5bf6369122b97..5a8b30c77c02e 100644 --- a/library/std/src/os/unix/io/fd.rs +++ b/library/std/src/os/unix/io/fd.rs @@ -99,7 +99,7 @@ impl FromRawFd for OwnedFd { /// # Safety /// /// The resource pointed to by `raw` must be open and suitable for assuming - /// ownership. + /// ownership. The resource must not require any cleanup other than `close`. #[inline] unsafe fn from_raw_fd(raw: RawFd) -> Self { assert_ne!(raw, -1i32); From a23ca7ceb1a3647b9671d929a6c4e4091a7935a7 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 21 Jul 2021 10:49:16 -0700 Subject: [PATCH 03/28] Update library/std/src/os/windows/io/handle.rs Co-authored-by: Josh Triplett --- library/std/src/os/windows/io/handle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index d881a67709d8f..3f9a146786c55 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -175,7 +175,7 @@ impl FromRawHandle for OwnedHandle { /// # Safety /// /// The resource pointed to by `raw` must be open and suitable for assuming - /// ownership. + /// ownership. The resource must not require any cleanup other than `CloseHandle`. #[inline] unsafe fn from_raw_handle(raw: RawHandle) -> Self { assert!(!raw.is_null()); From 1c6bf04edba84ce57f33516138a6aac1a52a9fcd Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:23:13 -0700 Subject: [PATCH 04/28] Update library/std/src/os/windows/io/socket.rs Co-authored-by: Josh Triplett --- library/std/src/os/windows/io/socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index e45b334690e91..28695042a2b0b 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -98,7 +98,7 @@ impl FromRawSocket for OwnedSocket { /// # Safety /// /// The resource pointed to by `raw` must be open and suitable for assuming - /// ownership. + /// ownership. The resource must not require cleanup other than `closesocket`. #[inline] unsafe fn from_raw_socket(raw: RawSocket) -> Self { debug_assert_ne!(raw, c::INVALID_SOCKET as RawSocket); From 1f8a450cdd1b8324765f19c3edd8ca2242682fb8 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 16:57:38 -0700 Subject: [PATCH 05/28] Add a test to ensure that RawFd is the size we assume it is. --- library/std/src/os/unix/io/fd.rs | 4 ++++ library/std/src/os/unix/io/fd/tests.rs | 11 +++++++++++ library/std/src/os/wasi/io/fd.rs | 4 ++++ library/std/src/os/wasi/io/fd/tests.rs | 11 +++++++++++ 4 files changed, 30 insertions(+) create mode 100644 library/std/src/os/unix/io/fd/tests.rs create mode 100644 library/std/src/os/wasi/io/fd/tests.rs diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs index 5a8b30c77c02e..6bb1fa15c173f 100644 --- a/library/std/src/os/unix/io/fd.rs +++ b/library/std/src/os/unix/io/fd.rs @@ -2,6 +2,10 @@ #![unstable(feature = "io_safety", issue = "87074")] +// Tests for this module +#[cfg(test)] +mod tests; + use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::fmt; use crate::fs; diff --git a/library/std/src/os/unix/io/fd/tests.rs b/library/std/src/os/unix/io/fd/tests.rs new file mode 100644 index 0000000000000..84d2a7a1a91b4 --- /dev/null +++ b/library/std/src/os/unix/io/fd/tests.rs @@ -0,0 +1,11 @@ +use crate::mem::size_of; +use crate::os::unix::io::RawFd; + +#[test] +fn test_raw_fd_layout() { + // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start` + // and `rustc_layout_scalar_valid_range_end`, with values that depend on + // the bit width of `RawFd`. If this ever changes, those values will need + // to be updated. + assert_eq!(size_of::(), 4); +} diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs index 494903d941c78..f9cacc841cd61 100644 --- a/library/std/src/os/wasi/io/fd.rs +++ b/library/std/src/os/wasi/io/fd.rs @@ -2,6 +2,10 @@ #![unstable(feature = "wasi_ext", issue = "71213")] +// Tests for this module +#[cfg(test)] +mod tests; + use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::fmt; use crate::fs; diff --git a/library/std/src/os/wasi/io/fd/tests.rs b/library/std/src/os/wasi/io/fd/tests.rs new file mode 100644 index 0000000000000..b276b7bafed80 --- /dev/null +++ b/library/std/src/os/wasi/io/fd/tests.rs @@ -0,0 +1,11 @@ +use std::mem::size_of; +use std::os::wasi::io::RawFd; + +#[test] +fn test_raw_fd_layout() { + /// `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start` + /// and `rustc_layout_scalar_valid_range_end`, with values that depend on + /// the bit width of `RawFd`. If this ever changes, those values will need + /// to be updated. + assert_eq!(size_of::(), 4); +} From 6b4dbdbf47a73de688df06d50dada7ba80df9458 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 16:58:38 -0700 Subject: [PATCH 06/28] Be more precise about `mmap` and undefined behavior. `mmap` doesn't *always* cause undefined behavior; it depends on the details of how you use it. --- library/std/src/os/unix/io/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 06f47cbb31f01..fd1394a0520d4 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -32,9 +32,9 @@ //! other code using that file descriptor. //! This list doesn't include `mmap`, since `mmap` does do a proper borrow of //! its file descriptor argument. That said, `mmap` is unsafe for other -//! reasons: it operates on raw pointers, and it has undefined behavior if the -//! underlying storage is mutated. Mutations may come from other processes, or -//! from the same process if the API provides `BorrowedFd` access, since as +//! reasons: it operates on raw pointers, and it can have undefined behavior if +//! the underlying storage is mutated. Mutations may come from other processes, +//! or from the same process if the API provides `BorrowedFd` access, since as //! mentioned earlier, `BorrowedFd` values may be used in APIs which provide //! safe access to any system call. Consequently, code using `mmap` and //! presenting a safe API must take full responsibility for ensuring that safe From 31f7bf82711a1d971e9d786a40c01f8d7088cd52 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 16:59:46 -0700 Subject: [PATCH 07/28] Add a comment about `OptionFileHandle`. --- library/std/src/os/windows/io/handle.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 3f9a146786c55..2d561ad476a2a 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -58,6 +58,10 @@ pub struct OwnedHandle { /// where `INVALID_HANDLE_VALUE` is used as the sentry value, and null values /// are not used at all, such as in the return value of `CreateFileW`. /// +/// The main thing you can do with an `OptionFileHandle` is to convert it into +/// an `OwnedHandle` using its [`TryFrom`] implementation, and this conversion +/// takes care of the check for `INVALID_HANDLE_VALUE`. +/// /// If this holds an owned handle, it closes the handle on drop. /// /// This uses `repr(transparent)` and has the representation of a host handle, From 926344a80f19fe255f0b13f4a13d9435bbb9e469 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:05:24 -0700 Subject: [PATCH 08/28] Add a comment about how `OwnedHandle` should not be used with registry handles. --- library/std/src/os/windows/io/handle.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 2d561ad476a2a..46c6caae54458 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -47,6 +47,13 @@ pub struct BorrowedHandle<'handle> { /// `INVALID_HANDLE_VALUE` instead of null, use [`OptionFileHandle`] instead /// of `Option`. /// +/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such, +/// it must not be used with handles to open registry keys which need to be +/// closed with [`RegCloseKey`] instead. +/// +/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle +/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey +/// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] @@ -178,8 +185,14 @@ impl FromRawHandle for OwnedHandle { /// /// # Safety /// - /// The resource pointed to by `raw` must be open and suitable for assuming - /// ownership. The resource must not require any cleanup other than `CloseHandle`. + /// The resource pointed to by `raw` must be open and suitable for + /// assuming ownership. The resource must not require any cleanup other + /// than `CloseHandle`. + /// + /// In particular, it must not be used with handles to open registry + /// keys which need to be closed with [`RegCloseKey`] instead. + /// + /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey #[inline] unsafe fn from_raw_handle(raw: RawHandle) -> Self { assert!(!raw.is_null()); From 45b5de3376bdfdd04222add3f42e39f933984993 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:05:55 -0700 Subject: [PATCH 09/28] Delete a spurious empty comment line. --- library/std/src/os/windows/io/handle.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 46c6caae54458..e9128684354fc 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -75,7 +75,6 @@ pub struct OwnedHandle { /// so it can be used in FFI in places where a non-null handle is passed as a /// consumed argument or returned as an owned value, or it is /// `INVALID_HANDLE_VALUE` indicating an error or an otherwise absent value. -/// #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OptionFileHandle { From 0cb69dec57f9ad279d7ceefad26cb0d2e16107bc Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:08:27 -0700 Subject: [PATCH 10/28] Rename `OwnedFd`'s private field to match it's debug output. --- library/std/src/os/unix/io/fd.rs | 34 ++++++------- library/std/src/os/wasi/io/fd.rs | 34 ++++++------- library/std/src/os/windows/io/handle.rs | 68 ++++++++++++------------- library/std/src/os/windows/io/socket.rs | 35 ++++++------- 4 files changed, 86 insertions(+), 85 deletions(-) diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs index 6bb1fa15c173f..2be6198092fca 100644 --- a/library/std/src/os/unix/io/fd.rs +++ b/library/std/src/os/unix/io/fd.rs @@ -32,7 +32,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[unstable(feature = "io_safety", issue = "87074")] pub struct BorrowedFd<'fd> { - raw: RawFd, + fd: RawFd, _phantom: PhantomData<&'fd OwnedFd>, } @@ -52,7 +52,7 @@ pub struct BorrowedFd<'fd> { #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedFd { - raw: RawFd, + fd: RawFd, } impl BorrowedFd<'_> { @@ -60,13 +60,13 @@ impl BorrowedFd<'_> { /// /// # Safety /// - /// The resource pointed to by `raw` must remain open for the duration of + /// The resource pointed to by `fd` must remain open for the duration of /// the returned `BorrowedFd`, and it must not have the value `-1`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_fd(raw: RawFd) -> Self { - assert_ne!(raw, -1_i32 as RawFd); - Self { raw, _phantom: PhantomData } + pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { + assert_ne!(fd, -1_i32 as RawFd); + Self { fd, _phantom: PhantomData } } } @@ -74,7 +74,7 @@ impl BorrowedFd<'_> { impl AsRawFd for BorrowedFd<'_> { #[inline] fn as_raw_fd(&self) -> RawFd { - self.raw + self.fd } } @@ -82,7 +82,7 @@ impl AsRawFd for BorrowedFd<'_> { impl AsRawFd for OwnedFd { #[inline] fn as_raw_fd(&self) -> RawFd { - self.raw + self.fd } } @@ -90,9 +90,9 @@ impl AsRawFd for OwnedFd { impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - let raw = self.raw; + let fd = self.fd; forget(self); - raw + fd } } @@ -102,13 +102,13 @@ impl FromRawFd for OwnedFd { /// /// # Safety /// - /// The resource pointed to by `raw` must be open and suitable for assuming + /// The resource pointed to by `fd` must be open and suitable for assuming /// ownership. The resource must not require any cleanup other than `close`. #[inline] - unsafe fn from_raw_fd(raw: RawFd) -> Self { - assert_ne!(raw, -1i32); + unsafe fn from_raw_fd(fd: RawFd) -> Self { + assert_ne!(fd, -1i32); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - Self { raw } + Self { fd } } } @@ -122,7 +122,7 @@ impl Drop for OwnedFd { // the file descriptor was closed or not, and if we retried (for // something like EINTR), we might close another valid file descriptor // opened after we closed ours. - let _ = libc::close(self.raw as raw::c_int); + let _ = libc::close(self.fd as raw::c_int); } } } @@ -130,14 +130,14 @@ impl Drop for OwnedFd { #[unstable(feature = "io_safety", issue = "87074")] impl fmt::Debug for BorrowedFd<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowedFd").field("fd", &self.raw).finish() + f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() } } #[unstable(feature = "io_safety", issue = "87074")] impl fmt::Debug for OwnedFd { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedFd").field("fd", &self.raw).finish() + f.debug_struct("OwnedFd").field("fd", &self.fd).finish() } } diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs index f9cacc841cd61..f77a73abb901f 100644 --- a/library/std/src/os/wasi/io/fd.rs +++ b/library/std/src/os/wasi/io/fd.rs @@ -32,7 +32,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[unstable(feature = "io_safety", issue = "87074")] pub struct BorrowedFd<'fd> { - raw: RawFd, + fd: RawFd, _phantom: PhantomData<&'fd OwnedFd>, } @@ -52,7 +52,7 @@ pub struct BorrowedFd<'fd> { #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedFd { - raw: RawFd, + fd: RawFd, } impl BorrowedFd<'_> { @@ -60,13 +60,13 @@ impl BorrowedFd<'_> { /// /// # Safety /// - /// The resource pointed to by `raw` must remain open for the duration of + /// The resource pointed to by `fd` must remain open for the duration of /// the returned `BorrowedFd`, and it must not have the value `-1`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_fd(raw: RawFd) -> Self { - assert_ne!(raw, -1_i32 as RawFd); - unsafe { Self { raw, _phantom: PhantomData } } + pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { + assert_ne!(fd, -1_i32 as RawFd); + unsafe { Self { fd, _phantom: PhantomData } } } } @@ -74,7 +74,7 @@ impl BorrowedFd<'_> { impl AsRawFd for BorrowedFd<'_> { #[inline] fn as_raw_fd(&self) -> RawFd { - self.raw + self.fd } } @@ -82,7 +82,7 @@ impl AsRawFd for BorrowedFd<'_> { impl AsRawFd for OwnedFd { #[inline] fn as_raw_fd(&self) -> RawFd { - self.raw + self.fd } } @@ -90,9 +90,9 @@ impl AsRawFd for OwnedFd { impl IntoRawFd for OwnedFd { #[inline] fn into_raw_fd(self) -> RawFd { - let raw = self.raw; + let fd = self.fd; forget(self); - raw + fd } } @@ -102,13 +102,13 @@ impl FromRawFd for OwnedFd { /// /// # Safety /// - /// The resource pointed to by `raw` must be open and suitable for assuming + /// The resource pointed to by `fd` must be open and suitable for assuming /// ownership. #[inline] - unsafe fn from_raw_fd(raw: RawFd) -> Self { - assert_ne!(raw, RawFd::MAX); + unsafe fn from_raw_fd(fd: RawFd) -> Self { + assert_ne!(fd, RawFd::MAX); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { raw } } + unsafe { Self { fd } } } } @@ -122,7 +122,7 @@ impl Drop for OwnedFd { // the file descriptor was closed or not, and if we retried (for // something like EINTR), we might close another valid file descriptor // opened after we closed ours. - let _ = libc::close(self.raw as raw::c_int); + let _ = libc::close(self.fd as raw::c_int); } } } @@ -130,14 +130,14 @@ impl Drop for OwnedFd { #[unstable(feature = "io_safety", issue = "87074")] impl fmt::Debug for BorrowedFd<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowedFd").field("fd", &self.raw).finish() + f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() } } #[unstable(feature = "io_safety", issue = "87074")] impl fmt::Debug for OwnedFd { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedFd").field("fd", &self.raw).finish() + f.debug_struct("OwnedFd").field("fd", &self.fd).finish() } } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index e9128684354fc..5d25052068579 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -30,7 +30,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct BorrowedHandle<'handle> { - raw: NonNull, + handle: NonNull, _phantom: PhantomData<&'handle OwnedHandle>, } @@ -58,7 +58,7 @@ pub struct BorrowedHandle<'handle> { #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedHandle { - raw: NonNull, + handle: NonNull, } /// Similar to `Option`, but intended for use in FFI interfaces @@ -78,7 +78,7 @@ pub struct OwnedHandle { #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OptionFileHandle { - raw: RawHandle, + handle: RawHandle, } // The Windows [`HANDLE`] type may be transferred across and shared between @@ -98,13 +98,13 @@ impl BorrowedHandle<'_> { /// /// # Safety /// - /// The resource pointed to by `raw` must remain open for the duration of - /// the returned `BorrowedHandle`, and it must not be null. + /// The resource pointed to by `handle` must remain open for the duration + /// of the returned `BorrowedHandle`, and it must not be null. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_handle(raw: RawHandle) -> Self { - assert!(!raw.is_null()); - Self { raw: NonNull::new_unchecked(raw), _phantom: PhantomData } + pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self { + assert!(!handle.is_null()); + Self { handle: NonNull::new_unchecked(handle), _phantom: PhantomData } } } @@ -113,7 +113,7 @@ impl OptionFileHandle { #[inline] #[unstable(feature = "io_safety", issue = "87074")] pub const fn none() -> Self { - Self { raw: c::INVALID_HANDLE_VALUE } + Self { handle: c::INVALID_HANDLE_VALUE } } } @@ -122,19 +122,19 @@ impl TryFrom for OwnedHandle { #[inline] fn try_from(option: OptionFileHandle) -> Result { - let raw = option.raw; + let handle = option.handle; forget(option); - if let Some(non_null) = NonNull::new(raw) { + if let Some(non_null) = NonNull::new(handle) { if non_null.as_ptr() != c::INVALID_HANDLE_VALUE { - Ok(Self { raw: non_null }) + Ok(Self { handle: non_null }) } else { Err(()) } } else { // In theory, we ought to be able to assume that the pointer here - // is never null, change `option.raw` to `NonNull`, and obviate the - // the panic path here. Unfortunately, Win32 documentation doesn't - // explicitly guarantee this anywhere. + // is never null, change `option.handle` to `NonNull`, and obviate + // the the panic path here. Unfortunately, Win32 documentation + // doesn't explicitly guarantee this anywhere. // // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a // null handle indicates an absent value, which wouldn't work if @@ -150,32 +150,32 @@ impl TryFrom for OwnedHandle { impl From for OptionFileHandle { #[inline] fn from(owned: OwnedHandle) -> Self { - let raw = owned.raw; + let handle = owned.handle; forget(owned); - Self { raw: raw.as_ptr() } + Self { handle: handle.as_ptr() } } } impl AsRawHandle for BorrowedHandle<'_> { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.raw.as_ptr() + self.handle.as_ptr() } } impl AsRawHandle for OwnedHandle { #[inline] fn as_raw_handle(&self) -> RawHandle { - self.raw.as_ptr() + self.handle.as_ptr() } } impl IntoRawHandle for OwnedHandle { #[inline] fn into_raw_handle(self) -> RawHandle { - let raw = self.raw.as_ptr(); + let handle = self.handle.as_ptr(); forget(self); - raw + handle } } @@ -184,7 +184,7 @@ impl FromRawHandle for OwnedHandle { /// /// # Safety /// - /// The resource pointed to by `raw` must be open and suitable for + /// The resource pointed to by `handle` must be open and suitable for /// assuming ownership. The resource must not require any cleanup other /// than `CloseHandle`. /// @@ -193,9 +193,9 @@ impl FromRawHandle for OwnedHandle { /// /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey #[inline] - unsafe fn from_raw_handle(raw: RawHandle) -> Self { - assert!(!raw.is_null()); - Self { raw: NonNull::new_unchecked(raw) } + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + assert!(!handle.is_null()); + Self { handle: NonNull::new_unchecked(handle) } } } @@ -204,16 +204,16 @@ impl FromRawHandle for OptionFileHandle { /// /// # Safety /// - /// The resource pointed to by `raw` must be either open and otherwise + /// The resource pointed to by `handle` must be either open and otherwise /// unowned, or equal to `INVALID_HANDLE_VALUE``. Note that not all Windows /// APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for the full /// story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] - unsafe fn from_raw_handle(raw: RawHandle) -> Self { - assert!(!raw.is_null()); - Self { raw } + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + assert!(!handle.is_null()); + Self { handle } } } @@ -221,7 +221,7 @@ impl Drop for OwnedHandle { #[inline] fn drop(&mut self) { unsafe { - let _ = c::CloseHandle(self.raw.as_ptr()); + let _ = c::CloseHandle(self.handle.as_ptr()); } } } @@ -230,26 +230,26 @@ impl Drop for OptionFileHandle { #[inline] fn drop(&mut self) { unsafe { - let _ = c::CloseHandle(self.raw); + let _ = c::CloseHandle(self.handle); } } } impl fmt::Debug for BorrowedHandle<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowedHandle").field("handle", &self.raw).finish() + f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish() } } impl fmt::Debug for OwnedHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedHandle").field("handle", &self.raw).finish() + f.debug_struct("OwnedHandle").field("handle", &self.handle).finish() } } impl fmt::Debug for OptionFileHandle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OptionFileHandle").field("handle", &self.raw).finish() + f.debug_struct("OptionFileHandle").field("handle", &self.handle).finish() } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 28695042a2b0b..fd89f4cc60c78 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -28,7 +28,7 @@ use crate::sys::c; )] #[unstable(feature = "io_safety", issue = "87074")] pub struct BorrowedSocket<'socket> { - raw: RawSocket, + socket: RawSocket, _phantom: PhantomData<&'socket OwnedSocket>, } @@ -50,7 +50,7 @@ pub struct BorrowedSocket<'socket> { )] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedSocket { - raw: RawSocket, + socket: RawSocket, } impl BorrowedSocket<'_> { @@ -63,32 +63,32 @@ impl BorrowedSocket<'_> { /// `INVALID_SOCKET`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_socket(raw: RawSocket) -> Self { - debug_assert_ne!(raw, c::INVALID_SOCKET as RawSocket); - Self { raw, _phantom: PhantomData } + pub unsafe fn borrow_raw_socket(socket: RawSocket) -> Self { + debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); + Self { socket, _phantom: PhantomData } } } impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.raw + self.socket } } impl AsRawSocket for OwnedSocket { #[inline] fn as_raw_socket(&self) -> RawSocket { - self.raw + self.socket } } impl IntoRawSocket for OwnedSocket { #[inline] fn into_raw_socket(self) -> RawSocket { - let raw = self.raw; + let socket = self.socket; forget(self); - raw + socket } } @@ -97,12 +97,13 @@ impl FromRawSocket for OwnedSocket { /// /// # Safety /// - /// The resource pointed to by `raw` must be open and suitable for assuming - /// ownership. The resource must not require cleanup other than `closesocket`. + /// The resource pointed to by `socket` must be open and suitable for + /// assuming ownership. The resource must not require cleanup other than + /// `closesocket`. #[inline] - unsafe fn from_raw_socket(raw: RawSocket) -> Self { - debug_assert_ne!(raw, c::INVALID_SOCKET as RawSocket); - Self { raw } + unsafe fn from_raw_socket(socket: RawSocket) -> Self { + debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); + Self { socket } } } @@ -110,20 +111,20 @@ impl Drop for OwnedSocket { #[inline] fn drop(&mut self) { unsafe { - let _ = c::closesocket(self.raw); + let _ = c::closesocket(self.socket); } } } impl fmt::Debug for BorrowedSocket<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowedSocket").field("socket", &self.raw).finish() + f.debug_struct("BorrowedSocket").field("socket", &self.socket).finish() } } impl fmt::Debug for OwnedSocket { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedSocket").field("socket", &self.raw).finish() + f.debug_struct("OwnedSocket").field("socket", &self.socket).finish() } } From 6486f89cbc7a041e5d48190a1f98e07af2bb842c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:12:40 -0700 Subject: [PATCH 11/28] Add Owned*, Borrowed*, and As* to the preludes. --- library/std/src/os/unix/mod.rs | 2 +- library/std/src/os/wasi/mod.rs | 2 +- library/std/src/os/windows/mod.rs | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index 6c73d4b21dd3d..17a0259572446 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -108,7 +108,7 @@ pub mod prelude { pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; + pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::process::{CommandExt, ExitStatusExt}; diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs index 1338aa271b33f..d767c149dc5d0 100644 --- a/library/std/src/os/wasi/mod.rs +++ b/library/std/src/os/wasi/mod.rs @@ -50,5 +50,5 @@ pub mod prelude { pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; + pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; } diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs index 52ac508f9f707..9c87e584b0cd2 100644 --- a/library/std/src/os/windows/mod.rs +++ b/library/std/src/os/windows/mod.rs @@ -32,8 +32,11 @@ pub mod prelude { pub use super::fs::{MetadataExt, OpenOptionsExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket}; + pub use super::io::{ + AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, FromRawHandle, FromRawSocket, + IntoRawHandle, IntoRawSocket, OptionFileHandle, OwnedHandle, OwnedSocket, + }; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket}; + pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket}; } From 6d7211738d74436a5d36ca68948d86f4809b9001 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:15:40 -0700 Subject: [PATCH 12/28] Add Safety comments to the `As*` for `Owned*` implementations. --- library/std/src/os/unix/io/fd.rs | 3 +++ library/std/src/os/wasi/io/fd.rs | 3 +++ library/std/src/os/windows/io/handle.rs | 3 +++ library/std/src/os/windows/io/socket.rs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs index 2be6198092fca..22b1151b92ad9 100644 --- a/library/std/src/os/unix/io/fd.rs +++ b/library/std/src/os/unix/io/fd.rs @@ -178,6 +178,9 @@ impl AsFd for BorrowedFd<'_> { impl AsFd for OwnedFd { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { + // Safety: `OwnedFd` and `BorrowedFd` have the same validity + // invariants, and the `BorrowdFd` is bounded by the lifetime + // of `&self`. unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } } } diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs index f77a73abb901f..e07c2e12b7d0b 100644 --- a/library/std/src/os/wasi/io/fd.rs +++ b/library/std/src/os/wasi/io/fd.rs @@ -177,6 +177,9 @@ impl AsFd for BorrowedFd<'_> { impl AsFd for OwnedFd { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { + // Safety: `OwnedFd` and `BorrowedFd` have the same validity + // invariants, and the `BorrowdFd` is bounded by the lifetime + // of `&self`. unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } } } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 5d25052068579..87fbd3e046086 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -282,6 +282,9 @@ impl AsHandle for BorrowedHandle<'_> { impl AsHandle for OwnedHandle { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { + // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity + // invariants, and the `BorrowdHandle` is bounded by the lifetime + // of `&self`. unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index fd89f4cc60c78..23db66df09f7a 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -145,6 +145,9 @@ impl AsSocket for BorrowedSocket<'_> { impl AsSocket for OwnedSocket { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { + // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity + // invariants, and the `BorrowdSocket` is bounded by the lifetime + // of `&self`. unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } } } From 1b35f7405ae2045d02c4739020d11c1480a8e01a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:32:04 -0700 Subject: [PATCH 13/28] Reword the description of dup2/dup3. --- library/std/src/os/unix/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index fd1394a0520d4..5a7682b50795c 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -28,7 +28,7 @@ //! - `close`, because that would end the dynamic lifetime of the resource //! without ending the lifetime of the file descriptor. //! - `dup2`/`dup3`, in the second argument, because this argument is -//! closed and replaced with a new resource, which may break the assumptions +//! closed and assigned a new resource, which may break the assumptions //! other code using that file descriptor. //! This list doesn't include `mmap`, since `mmap` does do a proper borrow of //! its file descriptor argument. That said, `mmap` is unsafe for other From 68964a7d6854826fd3cf4033f1a90dbb920f667b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 27 Jul 2021 17:33:55 -0700 Subject: [PATCH 14/28] Fix copypasta of "Unix" within the WASI directory. --- library/std/src/os/wasi/io/raw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs index 3e935e2502e9c..5e3d087344016 100644 --- a/library/std/src/os/wasi/io/raw.rs +++ b/library/std/src/os/wasi/io/raw.rs @@ -1,4 +1,4 @@ -//! Unix-specific extensions to general I/O primitives. +//! WASI-specific extensions to general I/O primitives. #![unstable(feature = "wasi_ext", issue = "71213")] From ab08639e5950f5c8a42a2870c9636181308c3686 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 28 Jul 2021 06:28:06 -0700 Subject: [PATCH 15/28] Add comments about impls for File, TcpStream, ChildStdin, etc. --- library/std/src/fs.rs | 6 ++++++ library/std/src/net/tcp.rs | 12 ++++++++++++ library/std/src/net/udp.rs | 6 ++++++ library/std/src/process.rs | 18 ++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 2c04481c04ec0..bdb172907ffed 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -587,6 +587,12 @@ impl File { } } +// In addition to the `impl`s here, `File` also has `impl`s for +// `AsFd`/`From`/`Into` and +// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and +// `AsHandle`/`From`/`Into` and +// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. + impl AsInner for File { fn as_inner(&self) -> &fs_imp::File { &self.inner diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 325acf0b97931..7f964e5c5a917 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -546,6 +546,12 @@ impl TcpStream { } } +// In addition to the `impl`s here, `TcpStream` also has `impl`s for +// `AsFd`/`From`/`Into` and +// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and +// `AsSocket`/`From`/`Into` and +// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows. + #[stable(feature = "rust1", since = "1.0.0")] impl Read for TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { @@ -908,6 +914,12 @@ impl TcpListener { } } +// In addition to the `impl`s here, `TcpListener` also has `impl`s for +// `AsFd`/`From`/`Into` and +// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and +// `AsSocket`/`From`/`Into` and +// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows. + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index d2088a12b2c7d..871505843af23 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -779,6 +779,12 @@ impl UdpSocket { } } +// In addition to the `impl`s here, `UdpSocket` also has `impl`s for +// `AsFd`/`From`/`Into` and +// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and +// `AsSocket`/`From`/`Into` and +// `AsRawSocket`/`IntoRawSocket`/`FromRawSocket` on Windows. + impl AsInner for UdpSocket { fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 diff --git a/library/std/src/process.rs b/library/std/src/process.rs index f5ce5210f8154..c9b21fcf9c6d2 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -258,6 +258,12 @@ pub struct ChildStdin { inner: AnonPipe, } +// In addition to the `impl`s here, `ChildStdin` also has `impl`s for +// `AsFd`/`From`/`Into` and +// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and +// `AsHandle`/`From`/`Into` and +// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. + #[stable(feature = "process", since = "1.0.0")] impl Write for ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -335,6 +341,12 @@ pub struct ChildStdout { inner: AnonPipe, } +// In addition to the `impl`s here, `ChildStdout` also has `impl`s for +// `AsFd`/`From`/`Into` and +// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and +// `AsHandle`/`From`/`Into` and +// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. + #[stable(feature = "process", since = "1.0.0")] impl Read for ChildStdout { fn read(&mut self, buf: &mut [u8]) -> io::Result { @@ -396,6 +408,12 @@ pub struct ChildStderr { inner: AnonPipe, } +// In addition to the `impl`s here, `ChildStderr` also has `impl`s for +// `AsFd`/`From`/`Into` and +// `AsRawFd`/`IntoRawFd`/`FromRawFd`, on Unix and WASI, and +// `AsHandle`/`From`/`Into` and +// `AsRawHandle`/`IntoRawHandle`/`FromRawHandle` on Windows. + #[stable(feature = "process", since = "1.0.0")] impl Read for ChildStderr { fn read(&mut self, buf: &mut [u8]) -> io::Result { From 907f00be3059deae7ccc0e95388501ff6f2b118d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 28 Jul 2021 06:52:45 -0700 Subject: [PATCH 16/28] Add more comments about the `INVALID_HANDLE_VALUE` situation. --- library/std/src/os/windows/io/handle.rs | 42 ++++++++++++++++++------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 87fbd3e046086..910b0ef9f5382 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -22,8 +22,8 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// so it can be used in FFI in places where a handle is passed as an argument, /// it is not captured or consumed, and it is never null. /// -/// Note that it *may* have the value `INVALID_HANDLE_VALUE`. See [here] for -/// the full story. +/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is +/// sometimes a valid handle value. See [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[derive(Copy, Clone)] @@ -42,10 +42,10 @@ pub struct BorrowedHandle<'handle> { /// so it can be used in FFI in places where a handle is passed as a consumed /// argument or returned as an owned value, and is never null. /// -/// Note that it *may* have the value `INVALID_HANDLE_VALUE`. See [here] for -/// the full story. For APIs like `CreateFileW` which report errors with -/// `INVALID_HANDLE_VALUE` instead of null, use [`OptionFileHandle`] instead -/// of `Option`. +/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is +/// sometimes a valid handle value. See [here] for the full story. For APIs +/// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead +/// of null, use [`OptionFileHandle`] instead of `Option`. /// /// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such, /// it must not be used with handles to open registry keys which need to be @@ -98,8 +98,14 @@ impl BorrowedHandle<'_> { /// /// # Safety /// - /// The resource pointed to by `handle` must remain open for the duration - /// of the returned `BorrowedHandle`, and it must not be null. + /// The resource pointed to by `handle` must be a valid open handle, it + /// must remain open for the duration of the returned `BorrowedHandle`, and + /// it must not be null. + /// + /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is + /// sometimes a valid handle value. See [here] for the full story. + /// + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] #[unstable(feature = "io_safety", issue = "87074")] pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self { @@ -182,6 +188,9 @@ impl IntoRawHandle for OwnedHandle { impl FromRawHandle for OwnedHandle { /// Constructs a new instance of `Self` from the given raw handle. /// + /// Use `OptionFileHandle` instead of `Option` for APIs that + /// use `INVALID_HANDLE_VALUE` to indicate failure. + /// /// # Safety /// /// The resource pointed to by `handle` must be open and suitable for @@ -191,7 +200,11 @@ impl FromRawHandle for OwnedHandle { /// In particular, it must not be used with handles to open registry /// keys which need to be closed with [`RegCloseKey`] instead. /// + /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is + /// sometimes a valid handle value. See [here] for the full story. + /// /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { assert!(!handle.is_null()); @@ -200,14 +213,19 @@ impl FromRawHandle for OwnedHandle { } impl FromRawHandle for OptionFileHandle { - /// Constructs a new instance of `Self` from the given raw handle. + /// Constructs a new instance of `Self` from the given raw handle returned + /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate + /// failure, such as `CreateFileW`. + /// + /// Use `Option` instead of `OptionFileHandle` for APIs that + /// use null to indicate failure. /// /// # Safety /// /// The resource pointed to by `handle` must be either open and otherwise - /// unowned, or equal to `INVALID_HANDLE_VALUE``. Note that not all Windows - /// APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for the full - /// story. + /// unowned, or equal to `INVALID_HANDLE_VALUE` (-1). It must not be null. + /// Note that not all Windows APIs use `INVALID_HANDLE_VALUE` for errors; + /// see [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] From 71dab738ac80c2dfadc0d83bb251c70d72d261d6 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 28 Jul 2021 07:02:51 -0700 Subject: [PATCH 17/28] Synchronize minor differences between Unix and WASI implementations. --- library/std/src/os/unix/io/fd.rs | 9 +++++---- library/std/src/os/wasi/io/fd.rs | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs index 22b1151b92ad9..f22da62555116 100644 --- a/library/std/src/os/unix/io/fd.rs +++ b/library/std/src/os/unix/io/fd.rs @@ -65,8 +65,9 @@ impl BorrowedFd<'_> { #[inline] #[unstable(feature = "io_safety", issue = "87074")] pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, -1_i32 as RawFd); - Self { fd, _phantom: PhantomData } + assert_ne!(fd, u32::MAX as RawFd); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { Self { fd, _phantom: PhantomData } } } } @@ -106,9 +107,9 @@ impl FromRawFd for OwnedFd { /// ownership. The resource must not require any cleanup other than `close`. #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, -1i32); + assert_ne!(fd, u32::MAX as RawFd); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - Self { fd } + unsafe { Self { fd } } } } diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs index e07c2e12b7d0b..8029ad68da931 100644 --- a/library/std/src/os/wasi/io/fd.rs +++ b/library/std/src/os/wasi/io/fd.rs @@ -65,7 +65,8 @@ impl BorrowedFd<'_> { #[inline] #[unstable(feature = "io_safety", issue = "87074")] pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, -1_i32 as RawFd); + assert_ne!(fd, u32::MAX as RawFd); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) unsafe { Self { fd, _phantom: PhantomData } } } } @@ -103,10 +104,10 @@ impl FromRawFd for OwnedFd { /// # Safety /// /// The resource pointed to by `fd` must be open and suitable for assuming - /// ownership. + /// ownership. The resource must not require any cleanup other than `close`. #[inline] unsafe fn from_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, RawFd::MAX); + assert_ne!(fd, u32::MAX as RawFd); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) unsafe { Self { fd } } } From 1dbd6d60f011dd048355ddb229bc78c366598746 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 28 Jul 2021 07:28:58 -0700 Subject: [PATCH 18/28] Factor out Unix and WASI fd code into a common module. --- library/std/src/os/fd.rs | 292 +++++++++++++++++++++++++++++++ library/std/src/os/mod.rs | 3 + library/std/src/os/unix/io/fd.rs | 282 +---------------------------- library/std/src/os/wasi/io/fd.rs | 281 +---------------------------- 4 files changed, 298 insertions(+), 560 deletions(-) create mode 100644 library/std/src/os/fd.rs diff --git a/library/std/src/os/fd.rs b/library/std/src/os/fd.rs new file mode 100644 index 0000000000000..e5a977d9e4044 --- /dev/null +++ b/library/std/src/os/fd.rs @@ -0,0 +1,292 @@ +//! Owned and borrowed Unix-like file descriptors. + +#![unstable(feature = "io_safety", issue = "87074")] +#![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(unix)] +use super::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(target_os = "wasi")] +use super::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::fmt; +use crate::fs; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::os::raw; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// A borrowed file descriptor. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the file descriptor. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as an argument, it is not captured or consumed, and it never has the +/// value `-1`. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct BorrowedFd<'fd> { + fd: RawFd, + _phantom: PhantomData<&'fd OwnedFd>, +} + +/// An owned file descriptor. +/// +/// This closes the file descriptor on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host file +/// descriptor, so it can be used in FFI in places where a file descriptor is +/// passed as a consumed argument or returned as an owned value, and it never +/// has the value `-1`. +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +#[unstable(feature = "io_safety", issue = "87074")] +pub struct OwnedFd { + fd: RawFd, +} + +impl BorrowedFd<'_> { + /// Return a `BorrowedFd` holding the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `fd` must remain open for the duration of + /// the returned `BorrowedFd`, and it must not have the value `-1`. + #[inline] + #[unstable(feature = "io_safety", issue = "87074")] + pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { + assert_ne!(fd, u32::MAX as RawFd); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { Self { fd, _phantom: PhantomData } } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsRawFd for BorrowedFd<'_> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsRawFd for OwnedFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl IntoRawFd for OwnedFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + let fd = self.fd; + forget(self); + fd + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl FromRawFd for OwnedFd { + /// Constructs a new instance of `Self` from the given raw file descriptor. + /// + /// # Safety + /// + /// The resource pointed to by `fd` must be open and suitable for assuming + /// ownership. The resource must not require any cleanup other than `close`. + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> Self { + assert_ne!(fd, u32::MAX as RawFd); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { Self { fd } } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl Drop for OwnedFd { + #[inline] + fn drop(&mut self) { + unsafe { + // Note that errors are ignored when closing a file descriptor. The + // reason for this is that if an error occurs we don't actually know if + // the file descriptor was closed or not, and if we retried (for + // something like EINTR), we might close another valid file descriptor + // opened after we closed ours. + let _ = libc::close(self.fd as raw::c_int); + } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Debug for BorrowedFd<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Debug for OwnedFd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedFd").field("fd", &self.fd).finish() + } +} + +/// A trait to borrow the file descriptor from an underlying object. +/// +/// This is only available on unix platforms and must be imported in order to +/// call the method. Windows platforms have a corresponding `AsHandle` and +/// `AsSocket` set of traits. +#[unstable(feature = "io_safety", issue = "87074")] +pub trait AsFd { + /// Borrows the file descriptor. + /// + /// # Example + /// + /// ```rust,no_run + /// # #![feature(io_safety)] + /// use std::fs::File; + /// # use std::io; + /// # #[cfg(target_os = "wasi")] + /// # use std::os::wasi::io::{AsFd, BorrowedFd}; + /// # #[cfg(unix)] + /// # use std::os::unix::io::{AsFd, BorrowedFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[unstable(feature = "io_safety", issue = "87074")] + fn as_fd(&self) -> BorrowedFd<'_>; +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for BorrowedFd<'_> { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + *self + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for OwnedFd { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + // Safety: `OwnedFd` and `BorrowedFd` have the same validity + // invariants, and the `BorrowdFd` is bounded by the lifetime + // of `&self`. + unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for fs::File { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(file: fs::File) -> OwnedFd { + file.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for fs::File { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::TcpStream { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { + tcp_stream.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::TcpStream { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::TcpListener { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { + tcp_listener.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::TcpListener { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::net::UdpSocket { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().socket().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { + udp_socket.into_inner().into_socket().into_inner().into_inner().into() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for crate::net::UdpSocket { + #[inline] + fn from(owned_fd: OwnedFd) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( + owned_fd, + )))) + } +} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 4c9814919cdfa..b68936a89a582 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -121,3 +121,6 @@ mod imp { #[cfg(not(doc))] #[stable(feature = "os", since = "1.0.0")] pub use imp::*; + +#[cfg(any(unix, target_os = "wasi"))] +mod fd; diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs index f22da62555116..728b20bfb58c2 100644 --- a/library/std/src/os/unix/io/fd.rs +++ b/library/std/src/os/unix/io/fd.rs @@ -6,287 +6,9 @@ #[cfg(test)] mod tests; -use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::fmt; -use crate::fs; -use crate::marker::PhantomData; -use crate::mem::forget; -use crate::os::raw; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{AsInner, IntoInner}; -/// A borrowed file descriptor. -/// -/// This has a lifetime parameter to tie it to the lifetime of something that -/// owns the file descriptor. -/// -/// This uses `repr(transparent)` and has the representation of a host file -/// descriptor, so it can be used in FFI in places where a file descriptor is -/// passed as an argument, it is not captured or consumed, and it never has the -/// value `-1`. -#[derive(Copy, Clone)] -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] -#[unstable(feature = "io_safety", issue = "87074")] -pub struct BorrowedFd<'fd> { - fd: RawFd, - _phantom: PhantomData<&'fd OwnedFd>, -} - -/// An owned file descriptor. -/// -/// This closes the file descriptor on drop. -/// -/// This uses `repr(transparent)` and has the representation of a host file -/// descriptor, so it can be used in FFI in places where a file descriptor is -/// passed as a consumed argument or returned as an owned value, and it never -/// has the value `-1`. -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] -#[unstable(feature = "io_safety", issue = "87074")] -pub struct OwnedFd { - fd: RawFd, -} - -impl BorrowedFd<'_> { - /// Return a `BorrowedFd` holding the given raw file descriptor. - /// - /// # Safety - /// - /// The resource pointed to by `fd` must remain open for the duration of - /// the returned `BorrowedFd`, and it must not have the value `-1`. - #[inline] - #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, u32::MAX as RawFd); - // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd, _phantom: PhantomData } } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsRawFd for BorrowedFd<'_> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsRawFd for OwnedFd { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl IntoRawFd for OwnedFd { - #[inline] - fn into_raw_fd(self) -> RawFd { - let fd = self.fd; - forget(self); - fd - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl FromRawFd for OwnedFd { - /// Constructs a new instance of `Self` from the given raw file descriptor. - /// - /// # Safety - /// - /// The resource pointed to by `fd` must be open and suitable for assuming - /// ownership. The resource must not require any cleanup other than `close`. - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, u32::MAX as RawFd); - // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd } } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl Drop for OwnedFd { - #[inline] - fn drop(&mut self) { - unsafe { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // opened after we closed ours. - let _ = libc::close(self.fd as raw::c_int); - } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl fmt::Debug for BorrowedFd<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl fmt::Debug for OwnedFd { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedFd").field("fd", &self.fd).finish() - } -} - -/// A trait to borrow the file descriptor from an underlying object. -/// -/// This is only available on unix platforms and must be imported in order to -/// call the method. Windows platforms have a corresponding `AsHandle` and -/// `AsSocket` set of traits. -#[unstable(feature = "io_safety", issue = "87074")] -pub trait AsFd { - /// Borrows the file descriptor. - /// - /// # Example - /// - /// ```rust,no_run - /// #![feature(io_safety)] - /// use std::fs::File; - /// # use std::io; - /// use std::os::unix::io::{AsFd, BorrowedFd}; - /// - /// let mut f = File::open("foo.txt")?; - /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); - /// # Ok::<(), io::Error>(()) - /// ``` - #[unstable(feature = "io_safety", issue = "87074")] - fn as_fd(&self) -> BorrowedFd<'_>; -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for BorrowedFd<'_> { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - *self - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for OwnedFd { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - // Safety: `OwnedFd` and `BorrowedFd` have the same validity - // invariants, and the `BorrowdFd` is bounded by the lifetime - // of `&self`. - unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for fs::File { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(file: fs::File) -> OwnedFd { - file.into_inner().into_inner().into_inner() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for fs::File { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::net::TcpStream { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().socket().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { - tcp_stream.into_inner().into_socket().into_inner().into_inner().into() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for crate::net::TcpStream { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( - owned_fd, - )))) - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::net::TcpListener { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().socket().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { - tcp_listener.into_inner().into_socket().into_inner().into_inner().into() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for crate::net::TcpListener { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( - owned_fd, - )))) - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::net::UdpSocket { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().socket().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { - udp_socket.into_inner().into_socket().into_inner().into_inner().into() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for crate::net::UdpSocket { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( - owned_fd, - )))) - } -} +pub use super::super::super::super::fd::*; #[unstable(feature = "io_safety", issue = "87074")] impl AsFd for crate::process::ChildStdin { diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs index 8029ad68da931..e46406e55690d 100644 --- a/library/std/src/os/wasi/io/fd.rs +++ b/library/std/src/os/wasi/io/fd.rs @@ -6,283 +6,4 @@ #[cfg(test)] mod tests; -use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::fmt; -use crate::fs; -use crate::marker::PhantomData; -use crate::mem::forget; -use crate::os::raw; -use crate::sys_common::{AsInner, FromInner, IntoInner}; - -/// A borrowed file descriptor. -/// -/// This has a lifetime parameter to tie it to the lifetime of something that -/// owns the file descriptor. -/// -/// This uses `repr(transparent)` and has the representation of a host file -/// descriptor, so it can be used in FFI in places where a file descriptor is -/// passed as an argument, it is not captured or consumed, and it never has the -/// value `-1`. -#[derive(Copy, Clone)] -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] -#[unstable(feature = "io_safety", issue = "87074")] -pub struct BorrowedFd<'fd> { - fd: RawFd, - _phantom: PhantomData<&'fd OwnedFd>, -} - -/// An owned file descriptor. -/// -/// This closes the file descriptor on drop. -/// -/// This uses `repr(transparent)` and has the representation of a host file -/// descriptor, so it can be used in FFI in places where a file descriptor is -/// passed as a consumed argument or returned as an owned value, and it never -/// has the value `-1`. -#[repr(transparent)] -#[rustc_layout_scalar_valid_range_start(0)] -// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a -// 32-bit c_int. Below is -2, in two's complement, but that only works out -// because c_int is 32 bits. -#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] -#[unstable(feature = "io_safety", issue = "87074")] -pub struct OwnedFd { - fd: RawFd, -} - -impl BorrowedFd<'_> { - /// Return a `BorrowedFd` holding the given raw file descriptor. - /// - /// # Safety - /// - /// The resource pointed to by `fd` must remain open for the duration of - /// the returned `BorrowedFd`, and it must not have the value `-1`. - #[inline] - #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, u32::MAX as RawFd); - // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd, _phantom: PhantomData } } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsRawFd for BorrowedFd<'_> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsRawFd for OwnedFd { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl IntoRawFd for OwnedFd { - #[inline] - fn into_raw_fd(self) -> RawFd { - let fd = self.fd; - forget(self); - fd - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl FromRawFd for OwnedFd { - /// Constructs a new instance of `Self` from the given raw file descriptor. - /// - /// # Safety - /// - /// The resource pointed to by `fd` must be open and suitable for assuming - /// ownership. The resource must not require any cleanup other than `close`. - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> Self { - assert_ne!(fd, u32::MAX as RawFd); - // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) - unsafe { Self { fd } } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl Drop for OwnedFd { - #[inline] - fn drop(&mut self) { - unsafe { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // opened after we closed ours. - let _ = libc::close(self.fd as raw::c_int); - } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl fmt::Debug for BorrowedFd<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("BorrowedFd").field("fd", &self.fd).finish() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl fmt::Debug for OwnedFd { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OwnedFd").field("fd", &self.fd).finish() - } -} - -/// A trait to borrow the file descriptor from an underlying object. -/// -/// This is only available on unix platforms and must be imported in order to -/// call the method. Windows platforms have a corresponding `AsHandle` and -/// `AsSocket` set of traits. -#[unstable(feature = "io_safety", issue = "87074")] -pub trait AsFd { - /// Borrows the file descriptor. - /// - /// # Example - /// - /// ```rust,no_run - /// use std::fs::File; - /// # use std::io; - /// use std::os::wasi::io::{AsFd, BorrowedFd}; - /// - /// let mut f = File::open("foo.txt")?; - /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); - /// # Ok::<(), io::Error>(()) - /// ``` - #[unstable(feature = "io_safety", issue = "87074")] - fn as_fd(&self) -> BorrowedFd<'_>; -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for BorrowedFd<'_> { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - *self - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for OwnedFd { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - // Safety: `OwnedFd` and `BorrowedFd` have the same validity - // invariants, and the `BorrowdFd` is bounded by the lifetime - // of `&self`. - unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for fs::File { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(file: fs::File) -> OwnedFd { - file.into_inner().into_inner().into_inner() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for fs::File { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::net::TcpStream { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().socket().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd { - tcp_stream.into_inner().into_socket().into_inner().into_inner().into() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for crate::net::TcpStream { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( - owned_fd, - )))) - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::net::TcpListener { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().socket().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd { - tcp_listener.into_inner().into_socket().into_inner().into_inner().into() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for crate::net::TcpListener { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( - owned_fd, - )))) - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::net::UdpSocket { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().socket().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd { - udp_socket.into_inner().into_socket().into_inner().into_inner().into() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for crate::net::UdpSocket { - #[inline] - fn from(owned_fd: OwnedFd) -> Self { - Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner( - owned_fd, - )))) - } -} +pub use super::super::super::super::fd::*; From 18a9f4628a44b2962dc8bd4b9b0026514effba2d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 28 Jul 2021 09:00:18 -0700 Subject: [PATCH 19/28] Don't encourage migration until io_safety is stablized. --- library/std/src/os/unix/io/mod.rs | 7 ++++--- library/std/src/os/windows/io/mod.rs | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 5a7682b50795c..0fd9591b0165a 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -17,9 +17,10 @@ //! Like raw pointers, `RawFd` values are primitive values. And in new code, //! they should be considered unsafe to do I/O on (analogous to dereferencing //! them). Rust did not always provide this guidance, so existing code in the -//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Libraries are -//! encouraged to migrate, either by adding `unsafe` to APIs that dereference -//! `RawFd` values, or by using to `BorrowedFd` or `OwnedFd` instead. +//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the +//! `io_safety` feature is stable, libraries will be encouraged to migrate, +//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by +//! using to `BorrowedFd` or `OwnedFd` instead. //! //! Like references, `BorrowedFd` values are tied to a lifetime, to ensure //! that they don't outlive the resource they point to. These are safe to diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs index d8e453bc0e040..2f6f076954809 100644 --- a/library/std/src/os/windows/io/mod.rs +++ b/library/std/src/os/windows/io/mod.rs @@ -23,10 +23,10 @@ //! And in new code, they should be considered unsafe to do I/O on (analogous //! to dereferencing them). Rust did not always provide this guidance, so //! existing code in the Rust ecosystem often doesn't mark `RawHandle` and -//! `RawSocket` usage as unsafe. Libraries are encouraged to migrate, either by -//! adding `unsafe` to APIs that dereference `RawHandle` and `RawSocket` -//! values, or by using to `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, -//! or `OwnedSocket`. +//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable, +//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs +//! that dereference `RawHandle` and `RawSocket` values, or by using to +//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`. //! //! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a //! lifetime, to ensure that they don't outlive the resource they point to. From 1ae1eeec2589abf742f87ec747acd31990e3b00a Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 29 Jul 2021 13:36:44 -0700 Subject: [PATCH 20/28] Rename OptionFileHandle to HandleOrInvalid and make it just wrap an Option The name (and updated documentation) make the FFI-only usage clearer, and wrapping Option avoids the need to write a separate Drop or Debug impl. Co-authored-by: Josh Triplett --- library/std/src/os/windows/io/handle.rs | 116 ++++++++---------------- library/std/src/os/windows/mod.rs | 2 +- 2 files changed, 38 insertions(+), 80 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 910b0ef9f5382..750a728d1cee8 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -45,7 +45,7 @@ pub struct BorrowedHandle<'handle> { /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is /// sometimes a valid handle value. See [here] for the full story. For APIs /// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead -/// of null, use [`OptionFileHandle`] instead of `Option`. +/// of null, use [`HandleOrInvalid`] instead of `Option`. /// /// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such, /// it must not be used with handles to open registry keys which need to be @@ -61,25 +61,21 @@ pub struct OwnedHandle { handle: NonNull, } -/// Similar to `Option`, but intended for use in FFI interfaces -/// where `INVALID_HANDLE_VALUE` is used as the sentry value, and null values -/// are not used at all, such as in the return value of `CreateFileW`. +/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used +/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses +/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such +/// FFI declarations. /// -/// The main thing you can do with an `OptionFileHandle` is to convert it into -/// an `OwnedHandle` using its [`TryFrom`] implementation, and this conversion -/// takes care of the check for `INVALID_HANDLE_VALUE`. +/// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an +/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for +/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without +/// checking for `INVALID_HANDLE_VALUE` first. /// -/// If this holds an owned handle, it closes the handle on drop. -/// -/// This uses `repr(transparent)` and has the representation of a host handle, -/// so it can be used in FFI in places where a non-null handle is passed as a -/// consumed argument or returned as an owned value, or it is -/// `INVALID_HANDLE_VALUE` indicating an error or an otherwise absent value. +/// If this holds a valid handle, it will close the handle on drop. #[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] -pub struct OptionFileHandle { - handle: RawHandle, -} +#[derive(Debug)] +pub struct HandleOrInvalid(Option); // The Windows [`HANDLE`] type may be transferred across and shared between // thread boundaries (despite containing a `*mut void`, which in general isn't @@ -87,10 +83,10 @@ pub struct OptionFileHandle { // // [`HANDLE`]: std::os::windows::raw::HANDLE unsafe impl Send for OwnedHandle {} -unsafe impl Send for OptionFileHandle {} +unsafe impl Send for HandleOrInvalid {} unsafe impl Send for BorrowedHandle<'_> {} unsafe impl Sync for OwnedHandle {} -unsafe impl Sync for OptionFileHandle {} +unsafe impl Sync for HandleOrInvalid {} unsafe impl Sync for BorrowedHandle<'_> {} impl BorrowedHandle<'_> { @@ -114,54 +110,31 @@ impl BorrowedHandle<'_> { } } -impl OptionFileHandle { - /// Return an empty `OptionFileHandle` with no resource. - #[inline] - #[unstable(feature = "io_safety", issue = "87074")] - pub const fn none() -> Self { - Self { handle: c::INVALID_HANDLE_VALUE } - } -} - -impl TryFrom for OwnedHandle { +impl TryFrom for OwnedHandle { type Error = (); #[inline] - fn try_from(option: OptionFileHandle) -> Result { - let handle = option.handle; - forget(option); - if let Some(non_null) = NonNull::new(handle) { - if non_null.as_ptr() != c::INVALID_HANDLE_VALUE { - Ok(Self { handle: non_null }) - } else { - Err(()) - } + fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { + // In theory, we ought to be able to assume that the pointer here is + // never null, use `OwnedHandle` rather than `Option`, and + // obviate the the panic path here. Unfortunately, Win32 documentation + // doesn't explicitly guarantee this anywhere. + // + // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a + // null handle indicates an absent value, which wouldn't work if null + // were a valid handle value, so it seems very unlikely that it could + // ever return null. But who knows? + // + // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!"); + if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE { + Err(()) } else { - // In theory, we ought to be able to assume that the pointer here - // is never null, change `option.handle` to `NonNull`, and obviate - // the the panic path here. Unfortunately, Win32 documentation - // doesn't explicitly guarantee this anywhere. - // - // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a - // null handle indicates an absent value, which wouldn't work if - // null were a valid handle value, so it seems very unlikely that - // it could ever return null. But who knows? - // - // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew - panic!("An `OptionFileHandle` was null!"); + Ok(owned_handle) } } } -impl From for OptionFileHandle { - #[inline] - fn from(owned: OwnedHandle) -> Self { - let handle = owned.handle; - forget(owned); - Self { handle: handle.as_ptr() } - } -} - impl AsRawHandle for BorrowedHandle<'_> { #[inline] fn as_raw_handle(&self) -> RawHandle { @@ -188,7 +161,7 @@ impl IntoRawHandle for OwnedHandle { impl FromRawHandle for OwnedHandle { /// Constructs a new instance of `Self` from the given raw handle. /// - /// Use `OptionFileHandle` instead of `Option` for APIs that + /// Use `HandleOrInvalid` instead of `Option` for APIs that /// use `INVALID_HANDLE_VALUE` to indicate failure. /// /// # Safety @@ -212,12 +185,12 @@ impl FromRawHandle for OwnedHandle { } } -impl FromRawHandle for OptionFileHandle { - /// Constructs a new instance of `Self` from the given raw handle returned +impl FromRawHandle for HandleOrInvalid { + /// Constructs a new instance of `Self` from the given `RawHandle` returned /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate /// failure, such as `CreateFileW`. /// - /// Use `Option` instead of `OptionFileHandle` for APIs that + /// Use `Option` instead of `HandleOrInvalid` for APIs that /// use null to indicate failure. /// /// # Safety @@ -230,8 +203,8 @@ impl FromRawHandle for OptionFileHandle { /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { - assert!(!handle.is_null()); - Self { handle } + // We require non-null here to catch errors earlier. + Self(Some(OwnedHandle::from_raw_handle(handle))) } } @@ -244,15 +217,6 @@ impl Drop for OwnedHandle { } } -impl Drop for OptionFileHandle { - #[inline] - fn drop(&mut self) { - unsafe { - let _ = c::CloseHandle(self.handle); - } - } -} - impl fmt::Debug for BorrowedHandle<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish() @@ -265,12 +229,6 @@ impl fmt::Debug for OwnedHandle { } } -impl fmt::Debug for OptionFileHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OptionFileHandle").field("handle", &self.handle).finish() - } -} - /// A trait to borrow the handle from an underlying object. #[unstable(feature = "io_safety", issue = "87074")] pub trait AsHandle { diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs index 9c87e584b0cd2..969054dd3b3dc 100644 --- a/library/std/src/os/windows/mod.rs +++ b/library/std/src/os/windows/mod.rs @@ -34,7 +34,7 @@ pub mod prelude { #[stable(feature = "rust1", since = "1.0.0")] pub use super::io::{ AsHandle, AsSocket, BorrowedHandle, BorrowedSocket, FromRawHandle, FromRawSocket, - IntoRawHandle, IntoRawSocket, OptionFileHandle, OwnedHandle, OwnedSocket, + HandleOrInvalid, IntoRawHandle, IntoRawSocket, OwnedHandle, OwnedSocket, }; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] From cada5fb336bac35eb34848f8619009dc7aa0f5d0 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 3 Aug 2021 07:31:59 -0500 Subject: [PATCH 21/28] Update PidFd for the new I/O safety APIs. --- library/std/src/os/linux/process.rs | 26 ++++++++++++++++--- .../std/src/sys/unix/process/process_unix.rs | 16 ++++++++---- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index 6daff0f003c8f..e3e7143c851ef 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -3,7 +3,7 @@ #![unstable(feature = "linux_pidfd", issue = "82971")] use crate::io::Result; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::process; use crate::sealed::Sealed; #[cfg(not(doc))] @@ -69,19 +69,37 @@ impl IntoInner for PidFd { impl AsRawFd for PidFd { fn as_raw_fd(&self) -> RawFd { - self.as_inner().raw() + self.as_inner().as_raw_fd() } } impl FromRawFd for PidFd { unsafe fn from_raw_fd(fd: RawFd) -> Self { - Self::from_inner(FileDesc::new(fd)) + Self::from_inner(FileDesc::from_raw_fd(fd)) } } impl IntoRawFd for PidFd { fn into_raw_fd(self) -> RawFd { - self.into_inner().into_raw() + self.into_inner().into_raw_fd() + } +} + +impl AsFd for PidFd { + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +impl From for PidFd { + fn from(fd: OwnedFd) -> Self { + Self::from_inner(FileDesc::from_inner(fd)) + } +} + +impl From for OwnedFd { + fn from(pid_fd: PidFd) -> Self { + pid_fd.into_inner().into_inner() } } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 4b210d6af1303..818f9308c1934 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -4,6 +4,7 @@ use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; use crate::os::raw::NonZero_c_int; +use crate::os::unix::io::FromRawFd; use crate::ptr; use crate::sys; use crate::sys::cvt; @@ -97,7 +98,9 @@ impl Command { drop(env_lock); drop(output); - let mut p = Process::new(pid, pidfd); + // Safety: We obtained the pidfd from calling `clone3` with + // `CLONE_PIDFD` so it's valid an otherwise unowned. + let mut p = unsafe { Process::new(pid, pidfd) }; let mut bytes = [0; 8]; // loop to handle EINTR @@ -446,7 +449,8 @@ impl Command { None => None, }; - let mut p = Process::new(0, -1); + // Safety: -1 indicates we don't have a pidfd. + let mut p = unsafe { Process::new(0, -1) }; struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit); @@ -545,14 +549,16 @@ pub struct Process { impl Process { #[cfg(target_os = "linux")] - fn new(pid: pid_t, pidfd: pid_t) -> Self { + unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self { use crate::sys_common::FromInner; - let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::new(pidfd))); + // Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned. + let pidfd = (pidfd >= 0) + .then(|| PidFd::from_inner(unsafe { sys::fd::FileDesc::from_raw_fd(pidfd) })); Process { pid, status: None, pidfd } } #[cfg(not(target_os = "linux"))] - fn new(pid: pid_t, _pidfd: pid_t) -> Self { + unsafe fn new(pid: pid_t, _pidfd: pid_t) -> Self { Process { pid, status: None } } From a7d9ab5835d662b1bc08ea3caeb1a5aa75f12cfc Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 4 Aug 2021 07:58:06 -0500 Subject: [PATCH 22/28] Fix an unused import warning. --- library/std/src/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 818f9308c1934..12edf04a4e2e9 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -4,7 +4,6 @@ use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; use crate::os::raw::NonZero_c_int; -use crate::os::unix::io::FromRawFd; use crate::ptr; use crate::sys; use crate::sys::cvt; @@ -550,6 +549,7 @@ pub struct Process { impl Process { #[cfg(target_os = "linux")] unsafe fn new(pid: pid_t, pidfd: pid_t) -> Self { + use crate::os::unix::io::FromRawFd; use crate::sys_common::FromInner; // Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned. let pidfd = (pidfd >= 0) From 9b99f8c4544e5670d8d589fd9164d75da90817de Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 6 Aug 2021 06:11:22 -0700 Subject: [PATCH 23/28] Remove the `#![feature(io_safety)]` from lib.rs. --- library/std/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index befb40cd2ed90..5e91a0cdbd6b5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -285,7 +285,6 @@ #![feature(int_log)] #![feature(into_future)] #![feature(intra_doc_pointers)] -#![feature(io_safety)] #![feature(iter_zip)] #![feature(lang_items)] #![feature(linkage)] From 6f872880b46d497166dfd33547c7b65125e35a26 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 12 Aug 2021 22:00:06 -0700 Subject: [PATCH 24/28] Use the correct `into_*` on Windows to avoid dropping a stdio handle. Use `into_raw_handle()` rather than `into_inner()` to completely consume a `Handle` without dropping its contained handle. --- library/std/src/sys/windows/process.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 5cfde16faf0b1..ccff90629a371 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -15,7 +15,7 @@ use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; use crate::os::windows::ffi::OsStrExt; -use crate::os::windows::io::{AsRawHandle, FromRawHandle}; +use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle}; use crate::path::Path; use crate::ptr; use crate::sys::c; @@ -371,7 +371,7 @@ impl Stdio { Ok(io) => unsafe { let io = Handle::from_raw_handle(io); let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS); - io.into_inner(); + io.into_raw_handle(); ret }, Err(..) => unsafe { Ok(Handle::from_raw_handle(c::INVALID_HANDLE_VALUE)) }, From 187ee5c824a72ad5a23b3b46d6b747ae27de2d18 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 17 Aug 2021 16:28:00 -0700 Subject: [PATCH 25/28] Add I/O safety trait impls for process::Stdio and process::Child. --- library/std/src/os/unix/process.rs | 12 +++++++++++- library/std/src/os/windows/process.rs | 26 +++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 1e794842e3c11..f2e8832cc9283 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -4,7 +4,7 @@ use crate::ffi::OsStr; use crate::io; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::process; use crate::sealed::Sealed; use crate::sys; @@ -327,6 +327,16 @@ impl FromRawFd for process::Stdio { } } +#[unstable(feature = "io_safety", issue = "87074")] +impl From for process::Stdio { + #[inline] + fn from(fd: OwnedFd) -> process::Stdio { + let fd = sys::fd::FileDesc::from_inner(fd); + let io = sys::process::Stdio::Fd(fd); + process::Stdio::from_inner(io) + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawFd for process::ChildStdin { #[inline] diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 56efb62d649a2..79c07d3b968fa 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -3,7 +3,7 @@ #![stable(feature = "process_extensions", since = "1.2.0")] use crate::ffi::OsStr; -use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle}; use crate::process; use crate::sealed::Sealed; use crate::sys; @@ -18,6 +18,15 @@ impl FromRawHandle for process::Stdio { } } +#[unstable(feature = "io_safety", issue = "87074")] +impl From for process::Stdio { + fn from(handle: OwnedHandle) -> process::Stdio { + let handle = sys::handle::Handle::from_handle(handle); + let io = sys::process::Stdio::Handle(handle); + process::Stdio::from_inner(io) + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::Child { #[inline] @@ -26,6 +35,14 @@ impl AsRawHandle for process::Child { } } +#[unstable(feature = "io_safety", issue = "87074")] +impl AsHandle for process::Child { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().handle().as_handle() + } +} + #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::Child { fn into_raw_handle(self) -> RawHandle { @@ -33,6 +50,13 @@ impl IntoRawHandle for process::Child { } } +#[unstable(feature = "io_safety", issue = "87074")] +impl IntoHandle for process::Child { + fn into_handle(self) -> BorrowedHandle<'_> { + self.into_inner().into_handle().into_handle() + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdin { #[inline] From 0377a633520344c6530f21fffee4d31768c9c447 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 19 Aug 2021 12:23:04 -0700 Subject: [PATCH 26/28] Fix syntax for non-doc comments, and use `crate::` instead of `std::`. --- library/std/src/os/wasi/io/fd/tests.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/std/src/os/wasi/io/fd/tests.rs b/library/std/src/os/wasi/io/fd/tests.rs index b276b7bafed80..418274752b0ad 100644 --- a/library/std/src/os/wasi/io/fd/tests.rs +++ b/library/std/src/os/wasi/io/fd/tests.rs @@ -1,11 +1,11 @@ -use std::mem::size_of; -use std::os::wasi::io::RawFd; +use crate::mem::size_of; +use crate::os::wasi::io::RawFd; #[test] fn test_raw_fd_layout() { - /// `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start` - /// and `rustc_layout_scalar_valid_range_end`, with values that depend on - /// the bit width of `RawFd`. If this ever changes, those values will need - /// to be updated. + // `OwnedFd` and `BorrowedFd` use `rustc_layout_scalar_valid_range_start` + // and `rustc_layout_scalar_valid_range_end`, with values that depend on + // the bit width of `RawFd`. If this ever changes, those values will need + // to be updated. assert_eq!(size_of::(), 4); } From e555003e6d6b6d71ce5509a6b6c7a15861208d6c Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 19 Aug 2021 12:24:25 -0700 Subject: [PATCH 27/28] Factor out a common `RawFd`/`AsRawFd`/etc for Unix and WASI. --- library/std/src/os/fd/mod.rs | 13 ++ .../src/os/{wasi/net/raw_fd.rs => fd/net.rs} | 7 +- library/std/src/os/{fd.rs => fd/owned.rs} | 8 +- library/std/src/os/fd/raw.rs | 206 ++++++++++++++++++ library/std/src/os/mod.rs | 2 +- library/std/src/os/unix/io/fd.rs | 52 +---- library/std/src/os/unix/io/raw.rs | 192 +--------------- library/std/src/os/unix/net/mod.rs | 3 - library/std/src/os/unix/net/raw_fd.rs | 43 ---- library/std/src/os/unix/process.rs | 50 ++++- library/std/src/os/wasi/io/fd.rs | 2 +- library/std/src/os/wasi/io/raw.rs | 181 +-------------- library/std/src/os/wasi/net/mod.rs | 5 - library/std/src/os/windows/process.rs | 12 +- library/std/src/sys/wasi/fd.rs | 103 ++++++--- library/std/src/sys/wasi/net.rs | 1 - 16 files changed, 355 insertions(+), 525 deletions(-) create mode 100644 library/std/src/os/fd/mod.rs rename library/std/src/os/{wasi/net/raw_fd.rs => fd/net.rs} (83%) rename library/std/src/os/{fd.rs => fd/owned.rs} (97%) create mode 100644 library/std/src/os/fd/raw.rs delete mode 100644 library/std/src/os/unix/net/raw_fd.rs diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs new file mode 100644 index 0000000000000..df11dc21aa7a6 --- /dev/null +++ b/library/std/src/os/fd/mod.rs @@ -0,0 +1,13 @@ +//! Owned and borrowed Unix-like file descriptors. + +#![unstable(feature = "io_safety", issue = "87074")] +#![deny(unsafe_op_in_unsafe_fn)] + +// `RawFd`, `AsRawFd`, etc. +pub mod raw; + +// `OwnedFd`, `AsFd`, etc. +pub mod owned; + +// Implementations for `AsRawFd` etc. for network types. +mod net; diff --git a/library/std/src/os/wasi/net/raw_fd.rs b/library/std/src/os/fd/net.rs similarity index 83% rename from library/std/src/os/wasi/net/raw_fd.rs rename to library/std/src/os/fd/net.rs index 201f4fbce390a..843f45f7f5f98 100644 --- a/library/std/src/os/wasi/net/raw_fd.rs +++ b/library/std/src/os/fd/net.rs @@ -1,5 +1,6 @@ -use crate::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::os::fd::owned::OwnedFd; +use crate::os::fd::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::{net, sys}; macro_rules! impl_as_raw_fd { @@ -23,7 +24,7 @@ macro_rules! impl_from_raw_fd { unsafe fn from_raw_fd(fd: RawFd) -> net::$t { unsafe { let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); - net::$t::from_inner(sys::net::$t::from_inner(socket)) + net::$t::from_inner(sys_common::net::$t::from_inner(socket)) } } } diff --git a/library/std/src/os/fd.rs b/library/std/src/os/fd/owned.rs similarity index 97% rename from library/std/src/os/fd.rs rename to library/std/src/os/fd/owned.rs index e5a977d9e4044..ecaec8b21d8a2 100644 --- a/library/std/src/os/fd.rs +++ b/library/std/src/os/fd/owned.rs @@ -3,15 +3,11 @@ #![unstable(feature = "io_safety", issue = "87074")] #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(unix)] -use super::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -#[cfg(target_os = "wasi")] -use super::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; -use crate::os::raw; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed file descriptor. @@ -123,7 +119,7 @@ impl Drop for OwnedFd { // the file descriptor was closed or not, and if we retried (for // something like EINTR), we might close another valid file descriptor // opened after we closed ours. - let _ = libc::close(self.fd as raw::c_int); + let _ = libc::close(self.fd); } } } diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs new file mode 100644 index 0000000000000..dcbce9f10b8da --- /dev/null +++ b/library/std/src/os/fd/raw.rs @@ -0,0 +1,206 @@ +//! Raw Unix-like file descriptors. + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::fs; +use crate::io; +use crate::os::raw; +#[cfg(unix)] +use crate::os::unix::io::OwnedFd; +#[cfg(target_os = "wasi")] +use crate::os::wasi::io::OwnedFd; +use crate::sys_common::{AsInner, IntoInner}; + +/// Raw file descriptors. +#[stable(feature = "rust1", since = "1.0.0")] +pub type RawFd = raw::c_int; + +/// A trait to extract the raw file descriptor from an underlying object. +/// +/// This is only available on unix and WASI platforms and must be imported in +/// order to call the method. Windows platforms have a corresponding +/// `AsRawHandle` and `AsRawSocket` set of traits. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This method does **not** pass ownership of the raw file descriptor + /// to the caller. The descriptor is only guaranteed to be valid while + /// the original object has not yet been destroyed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// #[cfg(unix)] + /// use std::os::unix::io::{AsRawFd, RawFd}; + /// #[cfg(target_os = "wasi")] + /// use std::os::wasi::io::{AsRawFd, RawFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// // Note that `raw_fd` is only valid as long as `f` exists. + /// let raw_fd: RawFd = f.as_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +#[stable(feature = "from_raw_os", since = "1.1.0")] +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function **consumes ownership** of the specified file + /// descriptor. The returned object will take responsibility for closing + /// it when the object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// #[cfg(unix)] + /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; + /// #[cfg(target_os = "wasi")] + /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// # Ok::<(), io::Error>(()) + /// ``` + #[stable(feature = "from_raw_os", since = "1.1.0")] + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +#[stable(feature = "into_raw_os", since = "1.4.0")] +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// #[cfg(unix)] + /// use std::os::unix::io::{IntoRawFd, RawFd}; + /// #[cfg(target_os = "wasi")] + /// use std::os::wasi::io::{IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[stable(feature = "into_raw_os", since = "1.4.0")] + fn into_raw_fd(self) -> RawFd; +} + +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for fs::File { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.as_inner().as_raw_fd() + } +} +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for fs::File { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> fs::File { + unsafe { fs::File::from(OwnedFd::from_raw_fd(fd)) } + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for fs::File { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_inner().into_raw_fd() + } +} + +#[stable(feature = "asraw_stdio", since = "1.21.0")] +impl AsRawFd for io::Stdin { + #[inline] + fn as_raw_fd(&self) -> RawFd { + libc::STDIN_FILENO + } +} + +#[stable(feature = "asraw_stdio", since = "1.21.0")] +impl AsRawFd for io::Stdout { + #[inline] + fn as_raw_fd(&self) -> RawFd { + libc::STDOUT_FILENO + } +} + +#[stable(feature = "asraw_stdio", since = "1.21.0")] +impl AsRawFd for io::Stderr { + #[inline] + fn as_raw_fd(&self) -> RawFd { + libc::STDERR_FILENO + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdinLock<'a> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + libc::STDIN_FILENO + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StdoutLock<'a> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + libc::STDOUT_FILENO + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawFd for io::StderrLock<'a> { + #[inline] + fn as_raw_fd(&self) -> RawFd { + libc::STDERR_FILENO + } +} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index b68936a89a582..79e6967300767 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -122,5 +122,5 @@ mod imp { #[stable(feature = "os", since = "1.0.0")] pub use imp::*; -#[cfg(any(unix, target_os = "wasi"))] +#[cfg(any(unix, target_os = "wasi", doc))] mod fd; diff --git a/library/std/src/os/unix/io/fd.rs b/library/std/src/os/unix/io/fd.rs index 728b20bfb58c2..7795db7abc01d 100644 --- a/library/std/src/os/unix/io/fd.rs +++ b/library/std/src/os/unix/io/fd.rs @@ -6,54 +6,4 @@ #[cfg(test)] mod tests; -use crate::sys_common::{AsInner, IntoInner}; - -pub use super::super::super::super::fd::*; - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::process::ChildStdin { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { - child_stdin.into_inner().into_inner().into_inner() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::process::ChildStdout { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { - child_stdout.into_inner().into_inner().into_inner() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl AsFd for crate::process::ChildStderr { - #[inline] - fn as_fd(&self) -> BorrowedFd<'_> { - self.as_inner().as_fd() - } -} - -#[unstable(feature = "io_safety", issue = "87074")] -impl From for OwnedFd { - #[inline] - fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { - child_stderr.into_inner().into_inner().into_inner() - } -} +pub use crate::os::fd::owned::*; diff --git a/library/std/src/os/unix/io/raw.rs b/library/std/src/os/unix/io/raw.rs index 78ee706d41dee..6317e31747119 100644 --- a/library/std/src/os/unix/io/raw.rs +++ b/library/std/src/os/unix/io/raw.rs @@ -2,194 +2,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::fs; -use crate::io; -use crate::os::raw; -use crate::os::unix::io::OwnedFd; -use crate::sys_common::{AsInner, IntoInner}; - -/// Raw file descriptors. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawFd = raw::c_int; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - /// - /// # Example - /// - /// ```no_run - /// use std::fs::File; - /// # use std::io; - /// use std::os::unix::io::{AsRawFd, RawFd}; - /// - /// let mut f = File::open("foo.txt")?; - /// // Note that `raw_fd` is only valid as long as `f` exists. - /// let raw_fd: RawFd = f.as_raw_fd(); - /// # Ok::<(), io::Error>(()) - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawFd { - /// Constructs a new instance of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - /// - /// # Example - /// - /// ```no_run - /// use std::fs::File; - /// # use std::io; - /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; - /// - /// let f = File::open("foo.txt")?; - /// let raw_fd: RawFd = f.into_raw_fd(); - /// // SAFETY: no other functions should call `from_raw_fd`, so there - /// // is only one owner for the file descriptor. - /// let f = unsafe { File::from_raw_fd(raw_fd) }; - /// # Ok::<(), io::Error>(()) - /// ``` - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - /// - /// # Example - /// - /// ```no_run - /// use std::fs::File; - /// # use std::io; - /// use std::os::unix::io::{IntoRawFd, RawFd}; - /// - /// let f = File::open("foo.txt")?; - /// let raw_fd: RawFd = f.into_raw_fd(); - /// # Ok::<(), io::Error>(()) - /// ``` - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_fd(self) -> RawFd; -} - -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl AsRawFd for RawFd { - #[inline] - fn as_raw_fd(&self) -> RawFd { - *self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl IntoRawFd for RawFd { - #[inline] - fn into_raw_fd(self) -> RawFd { - self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl FromRawFd for RawFd { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> RawFd { - fd - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for fs::File { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_raw_fd() - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for fs::File { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from(OwnedFd::from_raw_fd(fd)) - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for fs::File { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_inner().into_raw_fd() - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdin { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdout { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stderr { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdinLock<'a> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdoutLock<'a> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StderrLock<'a> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} +pub use crate::os::fd::raw::*; diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs index 3088ffb5e5c01..d462bd4b5f75e 100644 --- a/library/std/src/os/unix/net/mod.rs +++ b/library/std/src/os/unix/net/mod.rs @@ -25,7 +25,6 @@ mod addr; mod ancillary; mod datagram; mod listener; -mod raw_fd; mod stream; #[cfg(all(test, not(target_os = "emscripten")))] mod tests; @@ -48,7 +47,5 @@ pub use self::ancillary::*; pub use self::datagram::*; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::listener::*; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::raw_fd::*; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::stream::*; diff --git a/library/std/src/os/unix/net/raw_fd.rs b/library/std/src/os/unix/net/raw_fd.rs deleted file mode 100644 index 017caeebf7243..0000000000000 --- a/library/std/src/os/unix/net/raw_fd.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; -use crate::{net, sys}; - -macro_rules! impl_as_raw_fd { - ($($t:ident)*) => {$( - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for net::$t { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().socket().as_raw_fd() - } - } - )*}; -} -impl_as_raw_fd! { TcpStream TcpListener UdpSocket } - -macro_rules! impl_from_raw_fd { - ($($t:ident)*) => {$( - #[stable(feature = "from_raw_os", since = "1.1.0")] - impl FromRawFd for net::$t { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> net::$t { - let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd))); - net::$t::from_inner(sys_common::net::$t::from_inner(socket)) - } - } - )*}; -} -impl_from_raw_fd! { TcpStream TcpListener UdpSocket } - -macro_rules! impl_into_raw_fd { - ($($t:ident)*) => {$( - #[stable(feature = "into_raw_os", since = "1.4.0")] - impl IntoRawFd for net::$t { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner().into_inner().into_raw_fd() - } - } - )*}; -} -impl_into_raw_fd! { TcpStream TcpListener UdpSocket } diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index f2e8832cc9283..650dcbabbae8c 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -4,7 +4,7 @@ use crate::ffi::OsStr; use crate::io; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; +use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::process; use crate::sealed::Sealed; use crate::sys; @@ -385,6 +385,54 @@ impl IntoRawFd for process::ChildStderr { } } +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::process::ChildStdin { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { + child_stdin.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::process::ChildStdout { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { + child_stdout.into_inner().into_inner().into_inner() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl AsFd for crate::process::ChildStderr { + #[inline] + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl From for OwnedFd { + #[inline] + fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { + child_stderr.into_inner().into_inner().into_inner() + } +} + /// Returns the OS-assigned process identifier associated with this process's parent. #[stable(feature = "unix_ppid", since = "1.27.0")] pub fn parent_id() -> u32 { diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs index e46406e55690d..930aca887e3c4 100644 --- a/library/std/src/os/wasi/io/fd.rs +++ b/library/std/src/os/wasi/io/fd.rs @@ -6,4 +6,4 @@ #[cfg(test)] mod tests; -pub use super::super::super::super::fd::*; +pub use crate::os::fd::owned::*; diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs index 5e3d087344016..0e0c5824e3404 100644 --- a/library/std/src/os/wasi/io/raw.rs +++ b/library/std/src/os/wasi/io/raw.rs @@ -2,183 +2,4 @@ #![unstable(feature = "wasi_ext", issue = "71213")] -use crate::fs; -use crate::io; -use crate::net; -use crate::os::raw; -use crate::sys; -use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::os::wasi::io::OwnedFd; - -/// Raw file descriptors. -/// -/// This has type `c_int` to ease compatibility with code that also compiles on -/// Unix configurations, however unlike Unix and POSIX, in WASI negative file -/// descriptors are valid. Only `-1` is reserved for indicating errors. Code -/// intending to be portable across Unix platforms and WASI should avoid -/// assuming that negative file descriptors are invalid. -pub type RawFd = raw::c_int; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - /// - /// # Example - /// - /// ```no_run - /// use std::fs::File; - /// # use std::io; - /// use std::os::wasi::io::{AsRawFd, RawFd}; - /// - /// let mut f = File::open("foo.txt")?; - /// // Note that `raw_fd` is only valid as long as `f` exists. - /// let raw_fd: RawFd = f.as_raw_fd(); - /// # Ok::<(), io::Error>(()) - /// ``` - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -pub trait FromRawFd { - /// Constructs a new instance of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - /// - /// # Example - /// - /// ```no_run - /// use std::fs::File; - /// # use std::io; - /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd}; - /// - /// let f = File::open("foo.txt")?; - /// let raw_fd: RawFd = f.into_raw_fd(); - /// // SAFETY: no other functions should call `from_raw_fd`, so there - /// // is only one owner for the file descriptor. - /// let f = unsafe { File::from_raw_fd(raw_fd) }; - /// # Ok::<(), io::Error>(()) - /// ``` - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - /// - /// # Example - /// - /// ```no_run - /// use std::fs::File; - /// # use std::io; - /// use std::os::wasi::io::{IntoRawFd, RawFd}; - /// - /// let f = File::open("foo.txt")?; - /// let raw_fd: RawFd = f.into_raw_fd(); - /// # Ok::<(), io::Error>(()) - /// ``` - fn into_raw_fd(self) -> RawFd; -} - -impl AsRawFd for RawFd { - #[inline] - fn as_raw_fd(&self) -> RawFd { - *self - } -} -impl IntoRawFd for RawFd { - #[inline] - fn into_raw_fd(self) -> RawFd { - self - } -} -impl FromRawFd for RawFd { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> RawFd { - fd - } -} - -impl AsRawFd for fs::File { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.as_inner().as_raw_fd() - } -} -impl FromRawFd for fs::File { - #[inline] - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - unsafe { fs::File::from(OwnedFd::from_raw_fd(fd)) } - } -} -impl IntoRawFd for fs::File { - #[inline] - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_inner().into_raw_fd() - } -} - -impl AsRawFd for io::Stdin { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -impl AsRawFd for io::Stdout { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -impl AsRawFd for io::Stderr { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -impl<'a> AsRawFd for io::StdinLock<'a> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -impl<'a> AsRawFd for io::StdoutLock<'a> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -impl<'a> AsRawFd for io::StderrLock<'a> { - #[inline] - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} +pub use crate::os::fd::raw::*; diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs index 01b2c1033f7e7..e6bcf87887f03 100644 --- a/library/std/src/os/wasi/net/mod.rs +++ b/library/std/src/os/wasi/net/mod.rs @@ -1,8 +1,3 @@ //! WASI-specific networking functionality #![unstable(feature = "wasi_ext", issue = "71213")] - -mod raw_fd; - -#[unstable(feature = "wasi_ext", issue = "71213")] -pub use self::raw_fd::*; diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 79c07d3b968fa..b246599dfc0a9 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -3,7 +3,9 @@ #![stable(feature = "process_extensions", since = "1.2.0")] use crate::ffi::OsStr; -use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle}; +use crate::os::windows::io::{ + AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, +}; use crate::process; use crate::sealed::Sealed; use crate::sys; @@ -21,7 +23,7 @@ impl FromRawHandle for process::Stdio { #[unstable(feature = "io_safety", issue = "87074")] impl From for process::Stdio { fn from(handle: OwnedHandle) -> process::Stdio { - let handle = sys::handle::Handle::from_handle(handle); + let handle = sys::handle::Handle::from_inner(handle); let io = sys::process::Stdio::Handle(handle); process::Stdio::from_inner(io) } @@ -51,9 +53,9 @@ impl IntoRawHandle for process::Child { } #[unstable(feature = "io_safety", issue = "87074")] -impl IntoHandle for process::Child { - fn into_handle(self) -> BorrowedHandle<'_> { - self.into_inner().into_handle().into_handle() +impl From for OwnedHandle { + fn from(child: process::Child) -> OwnedHandle { + child.into_inner().into_handle().into_inner() } } diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 461afd2316f6f..e4f4456611cd0 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -5,7 +5,6 @@ use super::err2io; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; -use crate::os::raw::c_int; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; @@ -30,23 +29,25 @@ fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { impl WasiFd { pub fn datasync(&self) -> io::Result<()> { - unsafe { wasi::fd_datasync(self.as_raw_fd()).map_err(err2io) } + unsafe { wasi::fd_datasync(self.as_raw_fd() as wasi::Fd).map_err(err2io) } } pub fn pread(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - unsafe { wasi::fd_pread(self.as_raw_fd(), iovec(bufs), offset).map_err(err2io) } + unsafe { wasi::fd_pread(self.as_raw_fd() as wasi::Fd, iovec(bufs), offset).map_err(err2io) } } pub fn pwrite(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - unsafe { wasi::fd_pwrite(self.as_raw_fd(), ciovec(bufs), offset).map_err(err2io) } + unsafe { + wasi::fd_pwrite(self.as_raw_fd() as wasi::Fd, ciovec(bufs), offset).map_err(err2io) + } } pub fn read(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - unsafe { wasi::fd_read(self.as_raw_fd(), iovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_read(self.as_raw_fd() as wasi::Fd, iovec(bufs)).map_err(err2io) } } pub fn write(&self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { wasi::fd_write(self.as_raw_fd(), ciovec(bufs)).map_err(err2io) } + unsafe { wasi::fd_write(self.as_raw_fd() as wasi::Fd, ciovec(bufs)).map_err(err2io) } } pub fn seek(&self, pos: SeekFrom) -> io::Result { @@ -55,37 +56,42 @@ impl WasiFd { SeekFrom::End(pos) => (wasi::WHENCE_END, pos), SeekFrom::Current(pos) => (wasi::WHENCE_CUR, pos), }; - unsafe { wasi::fd_seek(self.as_raw_fd(), offset, whence).map_err(err2io) } + unsafe { wasi::fd_seek(self.as_raw_fd() as wasi::Fd, offset, whence).map_err(err2io) } } pub fn tell(&self) -> io::Result { - unsafe { wasi::fd_tell(self.as_raw_fd()).map_err(err2io) } + unsafe { wasi::fd_tell(self.as_raw_fd() as wasi::Fd).map_err(err2io) } } // FIXME: __wasi_fd_fdstat_get pub fn set_flags(&self, flags: wasi::Fdflags) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd(), flags).map_err(err2io) } + unsafe { wasi::fd_fdstat_set_flags(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) } } pub fn set_rights(&self, base: wasi::Rights, inheriting: wasi::Rights) -> io::Result<()> { - unsafe { wasi::fd_fdstat_set_rights(self.as_raw_fd(), base, inheriting).map_err(err2io) } + unsafe { + wasi::fd_fdstat_set_rights(self.as_raw_fd() as wasi::Fd, base, inheriting) + .map_err(err2io) + } } pub fn sync(&self) -> io::Result<()> { - unsafe { wasi::fd_sync(self.as_raw_fd()).map_err(err2io) } + unsafe { wasi::fd_sync(self.as_raw_fd() as wasi::Fd).map_err(err2io) } } pub fn advise(&self, offset: u64, len: u64, advice: wasi::Advice) -> io::Result<()> { - unsafe { wasi::fd_advise(self.as_raw_fd(), offset, len, advice).map_err(err2io) } + unsafe { + wasi::fd_advise(self.as_raw_fd() as wasi::Fd, offset, len, advice).map_err(err2io) + } } pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { - unsafe { wasi::fd_allocate(self.as_raw_fd(), offset, len).map_err(err2io) } + unsafe { wasi::fd_allocate(self.as_raw_fd() as wasi::Fd, offset, len).map_err(err2io) } } pub fn create_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_create_directory(self.as_raw_fd(), path).map_err(err2io) } + unsafe { wasi::path_create_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } pub fn link( @@ -96,8 +102,14 @@ impl WasiFd { new_path: &str, ) -> io::Result<()> { unsafe { - wasi::path_link(self.as_raw_fd(), old_flags, old_path, new_fd.as_raw_fd(), new_path) - .map_err(err2io) + wasi::path_link( + self.as_raw_fd() as wasi::Fd, + old_flags, + old_path, + new_fd.as_raw_fd() as wasi::Fd, + new_path, + ) + .map_err(err2io) } } @@ -112,7 +124,7 @@ impl WasiFd { ) -> io::Result { unsafe { wasi::path_open( - self.as_raw_fd(), + self.as_raw_fd() as wasi::Fd, dirflags, path, oflags, @@ -120,32 +132,39 @@ impl WasiFd { fs_rights_inheriting, fs_flags, ) - .map(|fd| WasiFd::from_raw_fd(fd)) + .map(|fd| WasiFd::from_raw_fd(fd as RawFd)) .map_err(err2io) } } pub fn readdir(&self, buf: &mut [u8], cookie: wasi::Dircookie) -> io::Result { unsafe { - wasi::fd_readdir(self.as_raw_fd(), buf.as_mut_ptr(), buf.len(), cookie).map_err(err2io) + wasi::fd_readdir(self.as_raw_fd() as wasi::Fd, buf.as_mut_ptr(), buf.len(), cookie) + .map_err(err2io) } } pub fn readlink(&self, path: &str, buf: &mut [u8]) -> io::Result { unsafe { - wasi::path_readlink(self.as_raw_fd(), path, buf.as_mut_ptr(), buf.len()).map_err(err2io) + wasi::path_readlink(self.as_raw_fd() as wasi::Fd, path, buf.as_mut_ptr(), buf.len()) + .map_err(err2io) } } pub fn rename(&self, old_path: &str, new_fd: &WasiFd, new_path: &str) -> io::Result<()> { unsafe { - wasi::path_rename(self.as_raw_fd(), old_path, new_fd.as_raw_fd(), new_path) - .map_err(err2io) + wasi::path_rename( + self.as_raw_fd() as wasi::Fd, + old_path, + new_fd.as_raw_fd() as wasi::Fd, + new_path, + ) + .map_err(err2io) } } pub fn filestat_get(&self) -> io::Result { - unsafe { wasi::fd_filestat_get(self.as_raw_fd()).map_err(err2io) } + unsafe { wasi::fd_filestat_get(self.as_raw_fd() as wasi::Fd).map_err(err2io) } } pub fn filestat_set_times( @@ -155,12 +174,13 @@ impl WasiFd { fstflags: wasi::Fstflags, ) -> io::Result<()> { unsafe { - wasi::fd_filestat_set_times(self.as_raw_fd(), atim, mtim, fstflags).map_err(err2io) + wasi::fd_filestat_set_times(self.as_raw_fd() as wasi::Fd, atim, mtim, fstflags) + .map_err(err2io) } } pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { - unsafe { wasi::fd_filestat_set_size(self.as_raw_fd(), size).map_err(err2io) } + unsafe { wasi::fd_filestat_set_size(self.as_raw_fd() as wasi::Fd, size).map_err(err2io) } } pub fn path_filestat_get( @@ -168,7 +188,9 @@ impl WasiFd { flags: wasi::Lookupflags, path: &str, ) -> io::Result { - unsafe { wasi::path_filestat_get(self.as_raw_fd(), flags, path).map_err(err2io) } + unsafe { + wasi::path_filestat_get(self.as_raw_fd() as wasi::Fd, flags, path).map_err(err2io) + } } pub fn path_filestat_set_times( @@ -180,21 +202,30 @@ impl WasiFd { fstflags: wasi::Fstflags, ) -> io::Result<()> { unsafe { - wasi::path_filestat_set_times(self.as_raw_fd(), flags, path, atim, mtim, fstflags) - .map_err(err2io) + wasi::path_filestat_set_times( + self.as_raw_fd() as wasi::Fd, + flags, + path, + atim, + mtim, + fstflags, + ) + .map_err(err2io) } } pub fn symlink(&self, old_path: &str, new_path: &str) -> io::Result<()> { - unsafe { wasi::path_symlink(old_path, self.as_raw_fd(), new_path).map_err(err2io) } + unsafe { + wasi::path_symlink(old_path, self.as_raw_fd() as wasi::Fd, new_path).map_err(err2io) + } } pub fn unlink_file(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_unlink_file(self.as_raw_fd(), path).map_err(err2io) } + unsafe { wasi::path_unlink_file(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } pub fn remove_directory(&self, path: &str) -> io::Result<()> { - unsafe { wasi::path_remove_directory(self.as_raw_fd(), path).map_err(err2io) } + unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) } } pub fn sock_recv( @@ -202,11 +233,15 @@ impl WasiFd { ri_data: &mut [IoSliceMut<'_>], ri_flags: wasi::Riflags, ) -> io::Result<(usize, wasi::Roflags)> { - unsafe { wasi::sock_recv(self.as_raw_fd(), iovec(ri_data), ri_flags).map_err(err2io) } + unsafe { + wasi::sock_recv(self.as_raw_fd() as wasi::Fd, iovec(ri_data), ri_flags).map_err(err2io) + } } pub fn sock_send(&self, si_data: &[IoSlice<'_>], si_flags: wasi::Siflags) -> io::Result { - unsafe { wasi::sock_send(self.as_raw_fd(), ciovec(si_data), si_flags).map_err(err2io) } + unsafe { + wasi::sock_send(self.as_raw_fd() as wasi::Fd, ciovec(si_data), si_flags).map_err(err2io) + } } pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -215,7 +250,7 @@ impl WasiFd { Shutdown::Write => wasi::SDFLAGS_WR, Shutdown::Both => wasi::SDFLAGS_WR | wasi::SDFLAGS_RD, }; - unsafe { wasi::sock_shutdown(self.as_raw_fd(), how).map_err(err2io) } + unsafe { wasi::sock_shutdown(self.as_raw_fd() as wasi::Fd, how).map_err(err2io) } } } diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index 1bd33f1e50e32..c7c4a9f6efdfb 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -5,7 +5,6 @@ use crate::convert::TryFrom; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; -use crate::os::raw::c_int; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::unsupported; use crate::sys_common::{AsInner, FromInner, IntoInner}; From b4dfa198bf4879bc159c7119bd4188ccd625f71d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 19 Aug 2021 16:15:29 -0700 Subject: [PATCH 28/28] Fix doc test failures on Windows. --- library/std/src/os/fd/owned.rs | 1 + library/std/src/os/fd/raw.rs | 4 ++++ library/std/src/os/windows/io/handle.rs | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index ecaec8b21d8a2..52d7d4690d39f 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -159,6 +159,7 @@ pub trait AsFd { /// # use std::os::unix::io::{AsFd, BorrowedFd}; /// /// let mut f = File::open("foo.txt")?; + /// # #[cfg(any(unix, target_os = "wasi"))] /// let borrowed_fd: BorrowedFd<'_> = f.as_fd(); /// # Ok::<(), io::Error>(()) /// ``` diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index dcbce9f10b8da..f874cf0b42d74 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -40,6 +40,7 @@ pub trait AsRawFd { /// /// let mut f = File::open("foo.txt")?; /// // Note that `raw_fd` is only valid as long as `f` exists. + /// #[cfg(any(unix, target_os = "wasi"))] /// let raw_fd: RawFd = f.as_raw_fd(); /// # Ok::<(), io::Error>(()) /// ``` @@ -75,9 +76,11 @@ pub trait FromRawFd { /// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd}; /// /// let f = File::open("foo.txt")?; + /// # #[cfg(any(unix, target_os = "wasi"))] /// let raw_fd: RawFd = f.into_raw_fd(); /// // SAFETY: no other functions should call `from_raw_fd`, so there /// // is only one owner for the file descriptor. + /// # #[cfg(any(unix, target_os = "wasi"))] /// let f = unsafe { File::from_raw_fd(raw_fd) }; /// # Ok::<(), io::Error>(()) /// ``` @@ -106,6 +109,7 @@ pub trait IntoRawFd { /// use std::os::wasi::io::{IntoRawFd, RawFd}; /// /// let f = File::open("foo.txt")?; + /// #[cfg(any(unix, target_os = "wasi"))] /// let raw_fd: RawFd = f.into_raw_fd(); /// # Ok::<(), io::Error>(()) /// ``` diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 750a728d1cee8..72a17adb3b470 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -237,9 +237,10 @@ pub trait AsHandle { /// # Example /// /// ```rust,no_run + /// # #![feature(io_safety)] /// use std::fs::File; /// # use std::io; - /// use std::os::windows::{AsHandle, BorrowedHandle}; + /// use std::os::windows::io::{AsHandle, BorrowedHandle}; /// /// let mut f = File::open("foo.txt")?; /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle();