use crate::io;
use crate::marker::PhantomData;
use crate::mem::forget;
+use crate::ptr;
use crate::sys::c;
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
/// And, it *may* have the value `NULL` (0), which can occur when consoles are
/// detached from processes, or when `windows_subsystem` is used.
///
+/// This type's `.to_owned()` implementation returns another `BorrowedHandle`
+/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw
+/// handle, which is then borrowed under the same lifetime.
+///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[derive(Copy, Clone)]
#[repr(transparent)]
/// [`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")]
pub struct OwnedHandle {
handle: RawHandle,
/// [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 {
+ pub unsafe fn borrow_raw(handle: RawHandle) -> Self {
Self { handle, _phantom: PhantomData }
}
}
#[inline]
fn try_from(handle_or_null: HandleOrNull) -> Result<Self, ()> {
let owned_handle = handle_or_null.0;
- if owned_handle.handle.is_null() { Err(()) } else { Ok(owned_handle) }
+ if owned_handle.handle.is_null() {
+ // Don't call `CloseHandle`; it'd be harmless, except that it could
+ // overwrite the `GetLastError` error.
+ forget(owned_handle);
+
+ Err(())
+ } else {
+ Ok(owned_handle)
+ }
}
}
inherit: bool,
options: c::DWORD,
) -> io::Result<Self> {
- let mut ret = 0 as c::HANDLE;
+ let handle = self.as_raw_handle();
+
+ // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as
+ // in a process with a detached console. `DuplicateHandle` would fail
+ // 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)) };
+ }
+
+ let mut ret = ptr::null_mut();
cvt(unsafe {
let cur_proc = c::GetCurrentProcess();
c::DuplicateHandle(
cur_proc,
- self.as_raw_handle(),
+ handle,
cur_proc,
&mut ret,
access,
#[inline]
fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
let owned_handle = handle_or_invalid.0;
- if owned_handle.handle == c::INVALID_HANDLE_VALUE { Err(()) } else { Ok(owned_handle) }
+ if owned_handle.handle == c::INVALID_HANDLE_VALUE {
+ // Don't call `CloseHandle`; it'd be harmless, except that it could
+ // overwrite the `GetLastError` error.
+ forget(owned_handle);
+
+ Err(())
+ } else {
+ Ok(owned_handle)
+ }
}
}
}
impl FromRawHandle for OwnedHandle {
- /// Constructs a new instance of `Self` from the given raw handle.
- ///
- /// # Safety
- ///
- /// The resource pointed to by `handle` 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.
- ///
- /// 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 {
Self { handle }
}
}
-impl FromRawHandle for HandleOrNull {
+impl HandleOrNull {
/// Constructs a new instance of `Self` from the given `RawHandle` returned
/// from a Windows API that uses null to indicate failure, such as
/// `CreateThread`.
///
/// # Safety
///
- /// The resource pointed to by `handle` must be either open and otherwise
- /// unowned, or null. Note that not all Windows APIs use null for errors;
- /// see [here] for the full story.
+ /// The passed `handle` value must either satisfy the safety requirements
+ /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all
+ /// Windows APIs use null for errors; see [here] for the full story.
///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[inline]
- unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
Self(OwnedHandle::from_raw_handle(handle))
}
}
-impl FromRawHandle for HandleOrInvalid {
+impl 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`.
///
/// # Safety
///
- /// The resource pointed to by `handle` must be either open and otherwise
- /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not
- /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for
- /// the full story.
+ /// The passed `handle` value must either satisfy the safety requirements
+ /// of [`FromRawHandle::from_raw_handle`], or be
+ /// `INVALID_HANDLE_VALUE` (-1). 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(handle: RawHandle) -> Self {
+ pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
Self(OwnedHandle::from_raw_handle(handle))
}
}
// 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()) }
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
}
}
impl AsHandle for crate::io::Stdin {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
- unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+ unsafe { BorrowedHandle::borrow_raw(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()) }
+ unsafe { BorrowedHandle::borrow_raw(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()) }
+ unsafe { BorrowedHandle::borrow_raw(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()) }
+ unsafe { BorrowedHandle::borrow_raw(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()) }
+ unsafe { BorrowedHandle::borrow_raw(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()) }
+ unsafe { BorrowedHandle::borrow_raw(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()) }
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
}
}
impl AsHandle for crate::process::ChildStdout {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
- unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
}
}
impl AsHandle for crate::process::ChildStderr {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
- unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
}
}
impl<T> AsHandle for crate::thread::JoinHandle<T> {
#[inline]
fn as_handle(&self) -> BorrowedHandle<'_> {
- unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) }
+ unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
}
}