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