about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-08-13 14:36:06 +0200
committerRalf Jung <post@ralfj.de>2023-08-13 15:07:57 +0200
commita473e95786fa2a1391903f2b3b31af5ae300a2d5 (patch)
tree1ad6d6784f5dfc421b9ba5806ef354743372b31e
parent1702d0fffc490e304cf93558c621f913ca062e62 (diff)
downloadrust-a473e95786fa2a1391903f2b3b31af5ae300a2d5.tar.gz
rust-a473e95786fa2a1391903f2b3b31af5ae300a2d5.zip
add more explicit I/O safety documentation
-rw-r--r--library/std/src/io/mod.rs36
-rw-r--r--library/std/src/os/fd/owned.rs12
-rw-r--r--library/std/src/os/fd/raw.rs5
-rw-r--r--library/std/src/os/fortanix_sgx/io.rs4
-rw-r--r--library/std/src/os/solid/io.rs4
-rw-r--r--library/std/src/os/unix/io/mod.rs3
-rw-r--r--library/std/src/os/windows/io/mod.rs3
7 files changed, 57 insertions, 10 deletions
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 5c1d2d8f46c..d2422cc1e40 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -5,7 +5,7 @@
 //! the [`Read`] and [`Write`] traits, which provide the
 //! most general interface for reading and writing input and output.
 //!
-//! # Read and Write
+//! ## Read and Write
 //!
 //! Because they are traits, [`Read`] and [`Write`] are implemented by a number
 //! of other types, and you can implement them for your types too. As such,
@@ -238,6 +238,35 @@
 //! contract. The implementation of many of these functions are subject to change over
 //! time and may call fewer or more syscalls/library functions.
 //!
+//! ## I/O Safety
+//!
+//! Rust follows an [I/O safety] discipline that is comparable to its memory safety discipline. This
+//! means that file descriptors can be *exclusively owned*. (Here, "file descriptor" is meant to
+//! subsume similar concepts that exist across a wide range of operating systems even if they might
+//! use a different name, such as "handle".) An exclusivley owned file descriptor is one that no
+//! other code is allowed to close, but the owner is allowed to close it any time. A type that owns
+//! its file descriptor should close it in its `drop` function. Types like [`File`] generally own
+//! their file descriptor. Similarly, file descriptors can be *borrowed*. This indicates that the
+//! file descriptor will not be closed for the lifetime of the borrow, but it does *not* imply any
+//! right to close this file descriptor, since it will likely be owned by someone else.
+//!
+//! The platform-specific parts of the Rust standard library expose types that reflect these
+//! concepts, see [`os::unix`] and [`os::windows`].
+//!
+//! To uphold I/O safety, it is crucial that no code closes file descriptors it does not own. In
+//! other words, a safe function that takes a regular integer, treats it as a file descriptor, and
+//! closes it, is *unsound*.
+//!
+//! Note that this does not talk about performing other operations on the file descriptor, such as
+//! reading or writing. For example, on Unix, the [`OwnedFd`] and [`BorrowedFd`] types from the
+//! standard library do *not* exclude that there is other code that reads or writes the same
+//! underlying object, and indeed there exist safe functions like `BorrowedFd::try_clone_to_owned`
+//! that can be used to read or write an object even after the end of the borrow. However, user code
+//! might want to rely on keeping the object behind a file descriptor completely private and
+//! protected against reads or writes from other parts of the program. Whether that is sound is
+//! [currently unclear](https://github.com/rust-lang/rust/issues/114167). Certainly, `OwnedFd` as a
+//! type does not provide any promise that the underlying file descriptor has not been cloned.
+//!
 //! [`File`]: crate::fs::File
 //! [`TcpStream`]: crate::net::TcpStream
 //! [`io::stdout`]: stdout
@@ -245,6 +274,11 @@
 //! [`?` operator]: ../../book/appendix-02-operators.html
 //! [`Result`]: crate::result::Result
 //! [`.unwrap()`]: crate::result::Result::unwrap
+//! [I/O safety]: https://rust-lang.github.io/rfcs/3128-io-safety.html
+//! [`os::unix`]: ../os/unix/io/index.html
+//! [`os::windows`]: ../os/windows/io/index.html
+//! [`OwnedFd`]: ../os/fd/struct.OwnedFd.html
+//! [`BorrowedFd`]: ../os/fd/struct.BorrowedFd.html
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 2180d2974d5..7861f1a3dfa 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -15,8 +15,9 @@ 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 has a lifetime parameter to tie it to the lifetime of something that owns the file
+/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close 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
@@ -42,7 +43,8 @@ pub struct BorrowedFd<'fd> {
 
 /// An owned file descriptor.
 ///
-/// This closes the file descriptor on drop.
+/// This closes the file descriptor on drop. It is guarantees that nobody else will close 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
@@ -155,7 +157,9 @@ impl FromRawFd for OwnedFd {
     /// # 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`.
+    /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
+    ///
+    /// [io-safety]: io#io-safety
     #[inline]
     unsafe fn from_raw_fd(fd: RawFd) -> Self {
         assert_ne!(fd, u32::MAX as RawFd);
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 592e072ad90..f80669ec708 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -84,7 +84,10 @@ pub trait FromRawFd {
     ///
     /// # Safety
     ///
-    /// The `fd` passed in must be a valid and open file descriptor.
+    /// The `fd` passed in must be an [owned file descriptor][io-safety];
+    /// in particular, it must be valid and open.
+    ///
+    /// [io-safety]: io#io-safety
     ///
     /// # Example
     ///
diff --git a/library/std/src/os/fortanix_sgx/io.rs b/library/std/src/os/fortanix_sgx/io.rs
index 7223ade6815..a7c22655653 100644
--- a/library/std/src/os/fortanix_sgx/io.rs
+++ b/library/std/src/os/fortanix_sgx/io.rs
@@ -31,10 +31,12 @@ pub trait FromRawFd {
     /// Constructs a new instance of `Self` from the given raw file
     /// descriptor and metadata.
     ///
-    /// This function **consumes ownership** of the specified file
+    /// This function **consumes [ownership][io-safety]** of the specified file
     /// descriptor. The returned object will take responsibility for closing
     /// it when the object goes out of scope.
     ///
+    /// [io-safety]: crate::io#io-safety
+    ///
     /// 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
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index 33cc5a015b5..5e6bf70ed4d 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -27,10 +27,12 @@ pub trait FromRawFd {
     /// Constructs a new instance of `Self` from the given raw file
     /// descriptor.
     ///
-    /// This function **consumes ownership** of the specified file
+    /// This function **consumes [ownership][io-safety]** of the specified file
     /// descriptor. The returned object will take responsibility for closing
     /// it when the object goes out of scope.
     ///
+    /// [io-safety]: crate::io#io-safety
+    ///
     /// 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
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
index 25b5dbff14f..b3070a61b68 100644
--- a/library/std/src/os/unix/io/mod.rs
+++ b/library/std/src/os/unix/io/mod.rs
@@ -6,7 +6,7 @@
 //!
 //! 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:
+//! analogous to types used for representing pointers. These types realize the Unix version of [I/O safety].
 //!
 //! | Type               | Analogous to |
 //! | ------------------ | ------------ |
@@ -74,6 +74,7 @@
 //! necessary to use *sandboxing*, which is outside the scope of `std`.
 //!
 //! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
+//! [I/O safety]: crate::io#io-safety
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
index e2a401fb696..9c304b8e990 100644
--- a/library/std/src/os/windows/io/mod.rs
+++ b/library/std/src/os/windows/io/mod.rs
@@ -6,7 +6,7 @@
 //!
 //! 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:
+//! analogous to types used for representing pointers. These types realize the Windows version of [I/O safety].
 //!
 //! | Type                   | Analogous to |
 //! | ---------------------- | ------------ |
@@ -47,6 +47,7 @@
 //!
 //! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
 //! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
+//! [I/O safety]: crate::io#io-safety
 
 #![stable(feature = "rust1", since = "1.0.0")]