about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDan Gohman <dev@sunfishcode.online>2021-07-29 13:36:44 -0700
committerDan Gohman <dev@sunfishcode.online>2021-08-19 12:02:40 -0700
commit1ae1eeec2589abf742f87ec747acd31990e3b00a (patch)
treecf2b1015fe0d737a080e1b13d7d73289cea21873
parent18a9f4628a44b2962dc8bd4b9b0026514effba2d (diff)
downloadrust-1ae1eeec2589abf742f87ec747acd31990e3b00a.tar.gz
rust-1ae1eeec2589abf742f87ec747acd31990e3b00a.zip
Rename OptionFileHandle to HandleOrInvalid and make it just wrap an Option<OwnedHandle>
The name (and updated documentation) make the FFI-only usage clearer, and wrapping Option<OwnedHandle> avoids the need to write a separate Drop or Debug impl.

Co-authored-by: Josh Triplett <josh@joshtriplett.org>
-rw-r--r--library/std/src/os/windows/io/handle.rs116
-rw-r--r--library/std/src/os/windows/mod.rs2
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 910b0ef9f53..750a728d1ce 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<OwnedHandle>`.
+/// of null, use [`HandleOrInvalid`] instead of `Option<OwnedHandle>`.
 ///
 /// `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<c_void>,
 }
 
-/// Similar to `Option<OwnedHandle>`, 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<OwnedHandle>);
 
 // 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<OptionFileHandle> for OwnedHandle {
+impl TryFrom<HandleOrInvalid> for OwnedHandle {
     type Error = ();
 
     #[inline]
-    fn try_from(option: OptionFileHandle) -> Result<Self, ()> {
-        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<Self, ()> {
+        // In theory, we ought to be able to assume that the pointer here is
+        // never null, use `OwnedHandle` rather than `Option<OwnedHandle>`, 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<OwnedHandle> 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<OwnedHandle>` for APIs that
+    /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` 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<OwnedHandle>` instead of `OptionFileHandle` for APIs that
+    /// Use `Option<OwnedHandle>` 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 9c87e584b0c..969054dd3b3 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")]