44
55use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
66use crate::convert::TryFrom;
7- use crate::ffi::c_void;
87use crate::fmt;
98use crate::fs;
109use crate::marker::PhantomData;
1110use crate::mem::forget;
12- use crate::ptr::NonNull;
1311use crate::sys::c;
1412use crate::sys_common::{AsInner, FromInner, IntoInner};
1513
@@ -20,32 +18,32 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
2018///
2119/// This uses `repr(transparent)` and has the representation of a host handle,
2220/// so it can be used in FFI in places where a handle is passed as an argument,
23- /// it is not captured or consumed, and it is never null .
21+ /// it is not captured or consumed.
2422///
2523/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
2624/// sometimes a valid handle value. See [here] for the full story.
2725///
26+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
27+ /// detached from processes, or when `windows_subsystem` is used.
28+ ///
2829/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
2930#[derive(Copy, Clone)]
3031#[repr(transparent)]
3132#[unstable(feature = "io_safety", issue = "87074")]
3233pub struct BorrowedHandle<'handle> {
33- handle: NonNull<c_void> ,
34+ handle: RawHandle ,
3435 _phantom: PhantomData<&'handle OwnedHandle>,
3536}
3637
3738/// An owned handle.
3839///
3940/// This closes the handle on drop.
4041///
41- /// This uses `repr(transparent)` and has the representation of a host handle,
42- /// so it can be used in FFI in places where a handle is passed as a consumed
43- /// argument or returned as an owned value, and is never null.
44- ///
4542/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
46- /// sometimes a valid handle value. See [here] for the full story. For APIs
47- /// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead
48- /// of null, use [`HandleOrInvalid`] instead of `Option<OwnedHandle>`.
43+ /// sometimes a valid handle value. See [here] for the full story.
44+ ///
45+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
46+ /// detached from processes, or when `windows_subsystem` is used.
4947///
5048/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
5149/// it must not be used with handles to open registry keys which need to be
@@ -55,12 +53,31 @@ pub struct BorrowedHandle<'handle> {
5553/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
5654///
5755/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
58- #[repr(transparent)]
5956#[unstable(feature = "io_safety", issue = "87074")]
6057pub struct OwnedHandle {
61- handle: NonNull<c_void> ,
58+ handle: RawHandle ,
6259}
6360
61+ /// FFI type for handles in return values or out parameters, where `NULL` is used
62+ /// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
63+ /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
64+ /// FFI declarations.
65+ ///
66+ /// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
67+ /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
68+ /// `NULL`. This ensures that such FFI calls cannot start using the handle without
69+ /// checking for `NULL` first.
70+ ///
71+ /// This type concerns any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
72+ /// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE`
73+ /// as special.
74+ ///
75+ /// If this holds a valid handle, it will close the handle on drop.
76+ #[repr(transparent)]
77+ #[unstable(feature = "io_safety", issue = "87074")]
78+ #[derive(Debug)]
79+ pub struct HandleOrNull(OwnedHandle);
80+
6481/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
6582/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
6683/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
@@ -71,21 +88,27 @@ pub struct OwnedHandle {
7188/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
7289/// checking for `INVALID_HANDLE_VALUE` first.
7390///
91+ /// This type concerns any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
92+ /// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL`
93+ /// under `windows_subsystem = "windows"` or other situations where I/O devices are detached.
94+ ///
7495/// If this holds a valid handle, it will close the handle on drop.
7596#[repr(transparent)]
7697#[unstable(feature = "io_safety", issue = "87074")]
7798#[derive(Debug)]
78- pub struct HandleOrInvalid(Option< OwnedHandle> );
99+ pub struct HandleOrInvalid(OwnedHandle);
79100
80101// The Windows [`HANDLE`] type may be transferred across and shared between
81102// thread boundaries (despite containing a `*mut void`, which in general isn't
82103// `Send` or `Sync`).
83104//
84105// [`HANDLE`]: std::os::windows::raw::HANDLE
85106unsafe impl Send for OwnedHandle {}
107+ unsafe impl Send for HandleOrNull {}
86108unsafe impl Send for HandleOrInvalid {}
87109unsafe impl Send for BorrowedHandle<'_> {}
88110unsafe impl Sync for OwnedHandle {}
111+ unsafe impl Sync for HandleOrNull {}
89112unsafe impl Sync for HandleOrInvalid {}
90113unsafe impl Sync for BorrowedHandle<'_> {}
91114
@@ -95,18 +118,29 @@ impl BorrowedHandle<'_> {
95118 /// # Safety
96119 ///
97120 /// The resource pointed to by `handle` must be a valid open handle, it
98- /// must remain open for the duration of the returned `BorrowedHandle`, and
99- /// it must not be null.
121+ /// must remain open for the duration of the returned `BorrowedHandle`.
100122 ///
101123 /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
102124 /// sometimes a valid handle value. See [here] for the full story.
103125 ///
126+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
127+ /// detached from processes, or when `windows_subsystem` is used.
128+ ///
104129 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
105130 #[inline]
106131 #[unstable(feature = "io_safety", issue = "87074")]
107132 pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self {
108- assert!(!handle.is_null());
109- Self { handle: NonNull::new_unchecked(handle), _phantom: PhantomData }
133+ Self { handle, _phantom: PhantomData }
134+ }
135+ }
136+
137+ impl TryFrom<HandleOrNull> for OwnedHandle {
138+ type Error = ();
139+
140+ #[inline]
141+ fn try_from(handle_or_null: HandleOrNull) -> Result<Self, ()> {
142+ let owned_handle = handle_or_null.0;
143+ if owned_handle.handle.is_null() { Err(()) } else { Ok(owned_handle) }
110144 }
111145}
112146
@@ -115,44 +149,29 @@ impl TryFrom<HandleOrInvalid> for OwnedHandle {
115149
116150 #[inline]
117151 fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
118- // In theory, we ought to be able to assume that the pointer here is
119- // never null, use `OwnedHandle` rather than `Option<OwnedHandle>`, and
120- // obviate the the panic path here. Unfortunately, Win32 documentation
121- // doesn't explicitly guarantee this anywhere.
122- //
123- // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a
124- // null handle indicates an absent value, which wouldn't work if null
125- // were a valid handle value, so it seems very unlikely that it could
126- // ever return null. But who knows?
127- //
128- // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
129- let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!");
130- if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE {
131- Err(())
132- } else {
133- Ok(owned_handle)
134- }
152+ let owned_handle = handle_or_invalid.0;
153+ if owned_handle.handle == c::INVALID_HANDLE_VALUE { Err(()) } else { Ok(owned_handle) }
135154 }
136155}
137156
138157impl AsRawHandle for BorrowedHandle<'_> {
139158 #[inline]
140159 fn as_raw_handle(&self) -> RawHandle {
141- self.handle.as_ptr()
160+ self.handle
142161 }
143162}
144163
145164impl AsRawHandle for OwnedHandle {
146165 #[inline]
147166 fn as_raw_handle(&self) -> RawHandle {
148- self.handle.as_ptr()
167+ self.handle
149168 }
150169}
151170
152171impl IntoRawHandle for OwnedHandle {
153172 #[inline]
154173 fn into_raw_handle(self) -> RawHandle {
155- let handle = self.handle.as_ptr() ;
174+ let handle = self.handle;
156175 forget(self);
157176 handle
158177 }
@@ -161,9 +180,6 @@ impl IntoRawHandle for OwnedHandle {
161180impl FromRawHandle for OwnedHandle {
162181 /// Constructs a new instance of `Self` from the given raw handle.
163182 ///
164- /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
165- /// use `INVALID_HANDLE_VALUE` to indicate failure.
166- ///
167183 /// # Safety
168184 ///
169185 /// The resource pointed to by `handle` must be open and suitable for
@@ -180,8 +196,28 @@ impl FromRawHandle for OwnedHandle {
180196 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
181197 #[inline]
182198 unsafe fn from_raw_handle(handle: RawHandle) -> Self {
183- assert!(!handle.is_null());
184- Self { handle: NonNull::new_unchecked(handle) }
199+ Self { handle }
200+ }
201+ }
202+
203+ impl FromRawHandle for HandleOrNull {
204+ /// Constructs a new instance of `Self` from the given `RawHandle` returned
205+ /// from a Windows API that uses null to indicate failure, such as
206+ /// `CreateThread`.
207+ ///
208+ /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
209+ /// use `INVALID_HANDLE_VALUE` to indicate failure.
210+ ///
211+ /// # Safety
212+ ///
213+ /// The resource pointed to by `handle` must be either open and otherwise
214+ /// unowned, or null. Note that not all Windows APIs use null for errors;
215+ /// see [here] for the full story.
216+ ///
217+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
218+ #[inline]
219+ unsafe fn from_raw_handle(handle: RawHandle) -> Self {
220+ Self(OwnedHandle::from_raw_handle(handle))
185221 }
186222}
187223
@@ -190,29 +226,28 @@ impl FromRawHandle for HandleOrInvalid {
190226 /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
191227 /// failure, such as `CreateFileW`.
192228 ///
193- /// Use `Option<OwnedHandle> ` instead of `HandleOrInvalid` for APIs that
229+ /// Use `HandleOrNull ` instead of `HandleOrInvalid` for APIs that
194230 /// use null to indicate failure.
195231 ///
196232 /// # Safety
197233 ///
198234 /// The resource pointed to by `handle` must be either open and otherwise
199- /// unowned, or equal to `INVALID_HANDLE_VALUE` (-1). It must not be null.
200- /// Note that not all Windows APIs use `INVALID_HANDLE_VALUE` for errors;
201- /// see [here] for the full story.
235+ /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not
236+ /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for
237+ /// the full story.
202238 ///
203239 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
204240 #[inline]
205241 unsafe fn from_raw_handle(handle: RawHandle) -> Self {
206- // We require non-null here to catch errors earlier.
207- Self(Some(OwnedHandle::from_raw_handle(handle)))
242+ Self(OwnedHandle::from_raw_handle(handle))
208243 }
209244}
210245
211246impl Drop for OwnedHandle {
212247 #[inline]
213248 fn drop(&mut self) {
214249 unsafe {
215- let _ = c::CloseHandle(self.handle.as_ptr() );
250+ let _ = c::CloseHandle(self.handle);
216251 }
217252 }
218253}
0 commit comments