Document that BorrowedFd may be used to do a dup.

This commit is contained in:
Dan Gohman 2022-05-19 06:41:35 -07:00
parent a4cec9742b
commit eb37bbcebc
4 changed files with 29 additions and 13 deletions

View File

@ -26,20 +26,30 @@
//! 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 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
//! 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
//! Rust code cannot evoke undefined behavior through it.
//!
//! `BorrowedFd` values may be used in APIs which provide safe access to `dup`
//! system calls, so types implementing `AsFd` or `From<OwnedFd>` should not
//! assume they always have exclusive access to the underlying file
//! description.
//!
//! `BorrowedFd` values may also be used with `mmap`, since `mmap` uses the
//! provided file descriptor in a manner similar to `dup` and does not require
//! the `BorrowedFd` passed to it to live for the lifetime of the resulting
//! mapping. That said, `mmap` is unsafe for other 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 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.

View File

@ -189,7 +189,7 @@ impl OwnedHandle {
access: c::DWORD,
inherit: bool,
options: c::DWORD,
) -> io::Result<Self> {
) -> io::Result<OwnedHandle> {
let handle = self.as_raw_handle();
// `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as
@ -197,7 +197,7 @@ impl OwnedHandle {
// if we passed it a null handle, but we can treat null as a valid
// handle which doesn't do any I/O, and allow it to be duplicated.
if handle.is_null() {
return unsafe { Ok(Self::from_raw_handle(handle)) };
return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) };
}
let mut ret = ptr::null_mut();
@ -213,7 +213,7 @@ impl OwnedHandle {
options,
)
})?;
unsafe { Ok(Self::from_raw_handle(ret)) }
unsafe { Ok(OwnedHandle::from_raw_handle(ret)) }
}
}

View File

@ -36,6 +36,12 @@
//! dynamic lifetime of the resource without ending the lifetime of the
//! handle or socket.
//!
//! `BorrowedHandle` and `BorrowedSocket` values may be used in APIs which
//! provide safe access to `DuplicateHandle` and `WSADuplicateSocketW` and
//! related functions, so types implementing `AsHandle`, `AsSocket`,
//! `From<OwnedHandle>`, or `From<OwnedSocket>` should not assume they always
//! have exclusive access to the underlying object.
//!
//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
//! resource they point to, and free (close) it when they are dropped.
//!

View File

@ -218,7 +218,7 @@ impl Handle {
inherit: bool,
options: c::DWORD,
) -> io::Result<Self> {
Ok(Self(self.0.duplicate(access, inherit, options)?))
Ok(Self(self.0.as_handle().duplicate(access, inherit, options)?))
}
/// Performs a synchronous read.