@@ -9,7 +9,6 @@ use crate::fmt;
9
9
use crate :: fs;
10
10
use crate :: marker:: PhantomData ;
11
11
use crate :: mem:: forget;
12
- use crate :: ptr:: NonNull ;
13
12
use crate :: sys:: c;
14
13
use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
15
14
@@ -20,32 +19,32 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
20
19
///
21
20
/// This uses `repr(transparent)` and has the representation of a host handle,
22
21
/// 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.
24
23
///
25
24
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
26
25
/// sometimes a valid handle value. See [here] for the full story.
27
26
///
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
+ ///
28
30
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
29
31
#[ derive( Copy , Clone ) ]
30
32
#[ repr( transparent) ]
31
33
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
32
34
pub struct BorrowedHandle < ' handle > {
33
- handle : NonNull < c_void > ,
35
+ handle : RawHandle ,
34
36
_phantom : PhantomData < & ' handle OwnedHandle > ,
35
37
}
36
38
37
39
/// An owned handle.
38
40
///
39
41
/// This closes the handle on drop.
40
42
///
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
- ///
45
43
/// 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.
49
48
///
50
49
/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
51
50
/// it must not be used with handles to open registry keys which need to be
@@ -55,12 +54,27 @@ pub struct BorrowedHandle<'handle> {
55
54
/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
56
55
///
57
56
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
58
- #[ repr( transparent) ]
59
57
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
60
58
pub struct OwnedHandle {
61
- handle : NonNull < c_void > ,
59
+ handle : RawHandle ,
62
60
}
63
61
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
+
64
78
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
65
79
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
66
80
/// `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 {
75
89
#[ repr( transparent) ]
76
90
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
77
91
#[ derive( Debug ) ]
78
- pub struct HandleOrInvalid ( Option < OwnedHandle > ) ;
92
+ pub struct HandleOrInvalid ( OwnedHandle ) ;
79
93
80
94
// The Windows [`HANDLE`] type may be transferred across and shared between
81
95
// thread boundaries (despite containing a `*mut void`, which in general isn't
82
96
// `Send` or `Sync`).
83
97
//
84
98
// [`HANDLE`]: std::os::windows::raw::HANDLE
85
99
unsafe impl Send for OwnedHandle { }
100
+ unsafe impl Send for HandleOrNull { }
86
101
unsafe impl Send for HandleOrInvalid { }
87
102
unsafe impl Send for BorrowedHandle < ' _ > { }
88
103
unsafe impl Sync for OwnedHandle { }
104
+ unsafe impl Sync for HandleOrNull { }
89
105
unsafe impl Sync for HandleOrInvalid { }
90
106
unsafe impl Sync for BorrowedHandle < ' _ > { }
91
107
@@ -95,18 +111,29 @@ impl BorrowedHandle<'_> {
95
111
/// # Safety
96
112
///
97
113
/// 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`.
100
115
///
101
116
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
102
117
/// sometimes a valid handle value. See [here] for the full story.
103
118
///
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
+ ///
104
122
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
105
123
#[ inline]
106
124
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
107
125
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) }
110
137
}
111
138
}
112
139
@@ -115,18 +142,7 @@ impl TryFrom<HandleOrInvalid> for OwnedHandle {
115
142
116
143
#[ inline]
117
144
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 ;
130
146
if owned_handle. handle . as_ptr ( ) == c:: INVALID_HANDLE_VALUE {
131
147
Err ( ( ) )
132
148
} else {
@@ -161,9 +177,6 @@ impl IntoRawHandle for OwnedHandle {
161
177
impl FromRawHandle for OwnedHandle {
162
178
/// Constructs a new instance of `Self` from the given raw handle.
163
179
///
164
- /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
165
- /// use `INVALID_HANDLE_VALUE` to indicate failure.
166
- ///
167
180
/// # Safety
168
181
///
169
182
/// The resource pointed to by `handle` must be open and suitable for
@@ -180,8 +193,28 @@ impl FromRawHandle for OwnedHandle {
180
193
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
181
194
#[ inline]
182
195
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) )
185
218
}
186
219
}
187
220
@@ -190,21 +223,20 @@ impl FromRawHandle for HandleOrInvalid {
190
223
/// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
191
224
/// failure, such as `CreateFileW`.
192
225
///
193
- /// Use `Option<OwnedHandle> ` instead of `HandleOrInvalid` for APIs that
226
+ /// Use `HandleOrNull ` instead of `HandleOrInvalid` for APIs that
194
227
/// use null to indicate failure.
195
228
///
196
229
/// # Safety
197
230
///
198
231
/// 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.
202
235
///
203
236
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
204
237
#[ inline]
205
238
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) )
208
240
}
209
241
}
210
242
0 commit comments