Skip to content

Commit a473e95

Browse files
committed
add more explicit I/O safety documentation
1 parent 1702d0f commit a473e95

File tree

7 files changed

+57
-10
lines changed

7 files changed

+57
-10
lines changed

library/std/src/io/mod.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! the [`Read`] and [`Write`] traits, which provide the
66
//! most general interface for reading and writing input and output.
77
//!
8-
//! # Read and Write
8+
//! ## Read and Write
99
//!
1010
//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
1111
//! of other types, and you can implement them for your types too. As such,
@@ -238,13 +238,47 @@
238238
//! contract. The implementation of many of these functions are subject to change over
239239
//! time and may call fewer or more syscalls/library functions.
240240
//!
241+
//! ## I/O Safety
242+
//!
243+
//! Rust follows an [I/O safety] discipline that is comparable to its memory safety discipline. This
244+
//! means that file descriptors can be *exclusively owned*. (Here, "file descriptor" is meant to
245+
//! subsume similar concepts that exist across a wide range of operating systems even if they might
246+
//! use a different name, such as "handle".) An exclusivley owned file descriptor is one that no
247+
//! other code is allowed to close, but the owner is allowed to close it any time. A type that owns
248+
//! its file descriptor should close it in its `drop` function. Types like [`File`] generally own
249+
//! their file descriptor. Similarly, file descriptors can be *borrowed*. This indicates that the
250+
//! file descriptor will not be closed for the lifetime of the borrow, but it does *not* imply any
251+
//! right to close this file descriptor, since it will likely be owned by someone else.
252+
//!
253+
//! The platform-specific parts of the Rust standard library expose types that reflect these
254+
//! concepts, see [`os::unix`] and [`os::windows`].
255+
//!
256+
//! To uphold I/O safety, it is crucial that no code closes file descriptors it does not own. In
257+
//! other words, a safe function that takes a regular integer, treats it as a file descriptor, and
258+
//! closes it, is *unsound*.
259+
//!
260+
//! Note that this does not talk about performing other operations on the file descriptor, such as
261+
//! reading or writing. For example, on Unix, the [`OwnedFd`] and [`BorrowedFd`] types from the
262+
//! standard library do *not* exclude that there is other code that reads or writes the same
263+
//! underlying object, and indeed there exist safe functions like `BorrowedFd::try_clone_to_owned`
264+
//! that can be used to read or write an object even after the end of the borrow. However, user code
265+
//! might want to rely on keeping the object behind a file descriptor completely private and
266+
//! protected against reads or writes from other parts of the program. Whether that is sound is
267+
//! [currently unclear](https://github.com/rust-lang/rust/issues/114167). Certainly, `OwnedFd` as a
268+
//! type does not provide any promise that the underlying file descriptor has not been cloned.
269+
//!
241270
//! [`File`]: crate::fs::File
242271
//! [`TcpStream`]: crate::net::TcpStream
243272
//! [`io::stdout`]: stdout
244273
//! [`io::Result`]: self::Result
245274
//! [`?` operator]: ../../book/appendix-02-operators.html
246275
//! [`Result`]: crate::result::Result
247276
//! [`.unwrap()`]: crate::result::Result::unwrap
277+
//! [I/O safety]: https://rust-lang.github.io/rfcs/3128-io-safety.html
278+
//! [`os::unix`]: ../os/unix/io/index.html
279+
//! [`os::windows`]: ../os/windows/io/index.html
280+
//! [`OwnedFd`]: ../os/fd/struct.OwnedFd.html
281+
//! [`BorrowedFd`]: ../os/fd/struct.BorrowedFd.html
248282
249283
#![stable(feature = "rust1", since = "1.0.0")]
250284

library/std/src/os/fd/owned.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
1515

1616
/// A borrowed file descriptor.
1717
///
18-
/// This has a lifetime parameter to tie it to the lifetime of something that
19-
/// owns the file descriptor.
18+
/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
19+
/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
20+
/// descriptor.
2021
///
2122
/// This uses `repr(transparent)` and has the representation of a host file
2223
/// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -42,7 +43,8 @@ pub struct BorrowedFd<'fd> {
4243

4344
/// An owned file descriptor.
4445
///
45-
/// This closes the file descriptor on drop.
46+
/// This closes the file descriptor on drop. It is guarantees that nobody else will close the file
47+
/// descriptor.
4648
///
4749
/// This uses `repr(transparent)` and has the representation of a host file
4850
/// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -155,7 +157,9 @@ impl FromRawFd for OwnedFd {
155157
/// # Safety
156158
///
157159
/// The resource pointed to by `fd` must be open and suitable for assuming
158-
/// ownership. The resource must not require any cleanup other than `close`.
160+
/// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
161+
///
162+
/// [io-safety]: io#io-safety
159163
#[inline]
160164
unsafe fn from_raw_fd(fd: RawFd) -> Self {
161165
assert_ne!(fd, u32::MAX as RawFd);

library/std/src/os/fd/raw.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ pub trait FromRawFd {
8484
///
8585
/// # Safety
8686
///
87-
/// The `fd` passed in must be a valid and open file descriptor.
87+
/// The `fd` passed in must be an [owned file descriptor][io-safety];
88+
/// in particular, it must be valid and open.
89+
///
90+
/// [io-safety]: io#io-safety
8891
///
8992
/// # Example
9093
///

library/std/src/os/fortanix_sgx/io.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ pub trait FromRawFd {
3131
/// Constructs a new instance of `Self` from the given raw file
3232
/// descriptor and metadata.
3333
///
34-
/// This function **consumes ownership** of the specified file
34+
/// This function **consumes [ownership][io-safety]** of the specified file
3535
/// descriptor. The returned object will take responsibility for closing
3636
/// it when the object goes out of scope.
3737
///
38+
/// [io-safety]: crate::io#io-safety
39+
///
3840
/// This function is also unsafe as the primitives currently returned
3941
/// have the contract that they are the sole owner of the file
4042
/// descriptor they are wrapping. Usage of this function could

library/std/src/os/solid/io.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ pub trait FromRawFd {
2727
/// Constructs a new instance of `Self` from the given raw file
2828
/// descriptor.
2929
///
30-
/// This function **consumes ownership** of the specified file
30+
/// This function **consumes [ownership][io-safety]** of the specified file
3131
/// descriptor. The returned object will take responsibility for closing
3232
/// it when the object goes out of scope.
3333
///
34+
/// [io-safety]: crate::io#io-safety
35+
///
3436
/// This function is also unsafe as the primitives currently returned
3537
/// have the contract that they are the sole owner of the file
3638
/// descriptor they are wrapping. Usage of this function could

library/std/src/os/unix/io/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//!
77
//! This module provides three types for representing file descriptors,
88
//! with different ownership properties: raw, borrowed, and owned, which are
9-
//! analogous to types used for representing pointers:
9+
//! analogous to types used for representing pointers. These types realize the Unix version of [I/O safety].
1010
//!
1111
//! | Type | Analogous to |
1212
//! | ------------------ | ------------ |
@@ -74,6 +74,7 @@
7474
//! necessary to use *sandboxing*, which is outside the scope of `std`.
7575
//!
7676
//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
77+
//! [I/O safety]: crate::io#io-safety
7778
7879
#![stable(feature = "rust1", since = "1.0.0")]
7980

library/std/src/os/windows/io/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//!
77
//! This module provides three types for representing raw handles and sockets
88
//! with different ownership properties: raw, borrowed, and owned, which are
9-
//! analogous to types used for representing pointers:
9+
//! analogous to types used for representing pointers. These types realize the Windows version of [I/O safety].
1010
//!
1111
//! | Type | Analogous to |
1212
//! | ---------------------- | ------------ |
@@ -47,6 +47,7 @@
4747
//!
4848
//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
4949
//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
50+
//! [I/O safety]: crate::io#io-safety
5051
5152
#![stable(feature = "rust1", since = "1.0.0")]
5253

0 commit comments

Comments
 (0)