@@ -9,7 +9,6 @@ use crate::fmt;
99use crate :: fs;
1010use crate :: marker:: PhantomData ;
1111use crate :: mem:: forget;
12- use crate :: ptr:: NonNull ;
1312use crate :: sys:: c;
1413use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
1514
@@ -20,32 +19,32 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
2019///
2120/// This uses `repr(transparent)` and has the representation of a host handle,
2221/// 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 .
22+ /// it is not captured or consumed.
2423///
2524/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
2625/// sometimes a valid handle value. See [here] for the full story.
2726///
27+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
28+ /// detached from processes, or when `windows_subsystem` is used.
29+ ///
2830/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
2931#[ derive( Copy , Clone ) ]
3032#[ repr( transparent) ]
3133#[ unstable( feature = "io_safety" , issue = "87074" ) ]
3234pub struct BorrowedHandle < ' handle > {
33- handle : NonNull < c_void > ,
35+ handle : RawHandle ,
3436 _phantom : PhantomData < & ' handle OwnedHandle > ,
3537}
3638
3739/// An owned handle.
3840///
3941/// This closes the handle on drop.
4042///
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- ///
4543/// 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>`.
44+ /// sometimes a valid handle value. See [here] for the full story.
45+ ///
46+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
47+ /// detached from processes, or when `windows_subsystem` is used.
4948///
5049/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
5150/// it must not be used with handles to open registry keys which need to be
@@ -55,12 +54,27 @@ pub struct BorrowedHandle<'handle> {
5554/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
5655///
5756/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
58- #[ repr( transparent) ]
5957#[ unstable( feature = "io_safety" , issue = "87074" ) ]
6058pub struct OwnedHandle {
61- handle : NonNull < c_void > ,
59+ handle : RawHandle ,
6260}
6361
62+ /// FFI type for handles in return values or out parameters, where `NULL` is used
63+ /// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
64+ /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
65+ /// FFI declarations.
66+ ///
67+ /// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
68+ /// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
69+ /// `NULL`. This ensures that such FFI calls cannot start using the handle without
70+ /// checking for `NULL` first.
71+ ///
72+ /// If this holds a valid handle, it will close the handle on drop.
73+ #[ repr( transparent) ]
74+ #[ unstable( feature = "io_safety" , issue = "87074" ) ]
75+ #[ derive( Debug ) ]
76+ pub struct HandleOrNull ( OwnedHandle ) ;
77+
6478/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
6579/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
6680/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
@@ -75,17 +89,19 @@ pub struct OwnedHandle {
7589#[ repr( transparent) ]
7690#[ unstable( feature = "io_safety" , issue = "87074" ) ]
7791#[ derive( Debug ) ]
78- pub struct HandleOrInvalid ( Option < OwnedHandle > ) ;
92+ pub struct HandleOrInvalid ( OwnedHandle ) ;
7993
8094// The Windows [`HANDLE`] type may be transferred across and shared between
8195// thread boundaries (despite containing a `*mut void`, which in general isn't
8296// `Send` or `Sync`).
8397//
8498// [`HANDLE`]: std::os::windows::raw::HANDLE
8599unsafe impl Send for OwnedHandle { }
100+ unsafe impl Send for HandleOrNull { }
86101unsafe impl Send for HandleOrInvalid { }
87102unsafe impl Send for BorrowedHandle < ' _ > { }
88103unsafe impl Sync for OwnedHandle { }
104+ unsafe impl Sync for HandleOrNull { }
89105unsafe impl Sync for HandleOrInvalid { }
90106unsafe impl Sync for BorrowedHandle < ' _ > { }
91107
@@ -95,18 +111,29 @@ impl BorrowedHandle<'_> {
95111 /// # Safety
96112 ///
97113 /// 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.
114+ /// must remain open for the duration of the returned `BorrowedHandle`.
100115 ///
101116 /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
102117 /// sometimes a valid handle value. See [here] for the full story.
103118 ///
119+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
120+ /// detached from processes, or when `windows_subsystem` is used.
121+ ///
104122 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
105123 #[ inline]
106124 #[ unstable( feature = "io_safety" , issue = "87074" ) ]
107125 pub unsafe fn borrow_raw_handle ( handle : RawHandle ) -> Self {
108- assert ! ( !handle. is_null( ) ) ;
109- Self { handle : NonNull :: new_unchecked ( handle) , _phantom : PhantomData }
126+ Self { handle, _phantom : PhantomData }
127+ }
128+ }
129+
130+ impl TryFrom < HandleOrNull > for OwnedHandle {
131+ type Error = ( ) ;
132+
133+ #[ inline]
134+ fn try_from ( handle_or_null : HandleOrNull ) -> Result < Self , ( ) > {
135+ let owned_handle = handle_or_null. 0 ;
136+ if owned_handle. handle . as_ptr ( ) . is_null ( ) { Err ( ( ) ) } else { Ok ( owned_handle) }
110137 }
111138}
112139
@@ -115,18 +142,7 @@ impl TryFrom<HandleOrInvalid> for OwnedHandle {
115142
116143 #[ inline]
117144 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!" ) ;
145+ let owned_handle = handle_or_invalid. 0 ;
130146 if owned_handle. handle . as_ptr ( ) == c:: INVALID_HANDLE_VALUE {
131147 Err ( ( ) )
132148 } else {
@@ -161,9 +177,6 @@ impl IntoRawHandle for OwnedHandle {
161177impl FromRawHandle for OwnedHandle {
162178 /// Constructs a new instance of `Self` from the given raw handle.
163179 ///
164- /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
165- /// use `INVALID_HANDLE_VALUE` to indicate failure.
166- ///
167180 /// # Safety
168181 ///
169182 /// The resource pointed to by `handle` must be open and suitable for
@@ -180,8 +193,28 @@ impl FromRawHandle for OwnedHandle {
180193 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
181194 #[ inline]
182195 unsafe fn from_raw_handle ( handle : RawHandle ) -> Self {
183- assert ! ( !handle. is_null( ) ) ;
184- Self { handle : NonNull :: new_unchecked ( handle) }
196+ Self { handle }
197+ }
198+ }
199+
200+ impl FromRawHandle for HandleOrNull {
201+ /// Constructs a new instance of `Self` from the given `RawHandle` returned
202+ /// from a Windows API that uses null to indicate failure, such as
203+ /// `CreateThread`.
204+ ///
205+ /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
206+ /// use `INVALID_HANDLE_VALUE` to indicate failure.
207+ ///
208+ /// # Safety
209+ ///
210+ /// The resource pointed to by `handle` must be either open and otherwise
211+ /// unowned, or null. Note that not all Windows APIs use null for errors;
212+ /// see [here] for the full story.
213+ ///
214+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
215+ #[ inline]
216+ unsafe fn from_raw_handle ( handle : RawHandle ) -> Self {
217+ Self ( OwnedHandle :: from_raw_handle ( handle) )
185218 }
186219}
187220
@@ -190,21 +223,20 @@ impl FromRawHandle for HandleOrInvalid {
190223 /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
191224 /// failure, such as `CreateFileW`.
192225 ///
193- /// Use `Option<OwnedHandle> ` instead of `HandleOrInvalid` for APIs that
226+ /// Use `HandleOrNull ` instead of `HandleOrInvalid` for APIs that
194227 /// use null to indicate failure.
195228 ///
196229 /// # Safety
197230 ///
198231 /// 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.
232+ /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not
233+ /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for
234+ /// the full story.
202235 ///
203236 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
204237 #[ inline]
205238 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) ) )
239+ Self ( OwnedHandle :: from_raw_handle ( handle) )
208240 }
209241}
210242
0 commit comments