4
4
5
5
use super :: raw:: { AsRawHandle , FromRawHandle , IntoRawHandle , RawHandle } ;
6
6
use crate :: convert:: TryFrom ;
7
- use crate :: ffi:: c_void;
8
7
use crate :: fmt;
9
8
use crate :: fs;
10
9
use crate :: marker:: PhantomData ;
11
10
use crate :: mem:: forget;
12
- use crate :: ptr:: NonNull ;
13
11
use crate :: sys:: c;
14
12
use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
15
13
@@ -20,32 +18,32 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
20
18
///
21
19
/// This uses `repr(transparent)` and has the representation of a host handle,
22
20
/// 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.
24
22
///
25
23
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
26
24
/// sometimes a valid handle value. See [here] for the full story.
27
25
///
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
+ ///
28
29
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
29
30
#[ derive( Copy , Clone ) ]
30
31
#[ repr( transparent) ]
31
32
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
32
33
pub struct BorrowedHandle < ' handle > {
33
- handle : NonNull < c_void > ,
34
+ handle : RawHandle ,
34
35
_phantom : PhantomData < & ' handle OwnedHandle > ,
35
36
}
36
37
37
38
/// An owned handle.
38
39
///
39
40
/// This closes the handle on drop.
40
41
///
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
42
/// 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.
49
47
///
50
48
/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
51
49
/// it must not be used with handles to open registry keys which need to be
@@ -55,12 +53,31 @@ pub struct BorrowedHandle<'handle> {
55
53
/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
56
54
///
57
55
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
58
- #[ repr( transparent) ]
59
56
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
60
57
pub struct OwnedHandle {
61
- handle : NonNull < c_void > ,
58
+ handle : RawHandle ,
62
59
}
63
60
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
+
64
81
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
65
82
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
66
83
/// `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 {
71
88
/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
72
89
/// checking for `INVALID_HANDLE_VALUE` first.
73
90
///
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
+ ///
74
95
/// If this holds a valid handle, it will close the handle on drop.
75
96
#[ repr( transparent) ]
76
97
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
77
98
#[ derive( Debug ) ]
78
- pub struct HandleOrInvalid ( Option < OwnedHandle > ) ;
99
+ pub struct HandleOrInvalid ( OwnedHandle ) ;
79
100
80
101
// The Windows [`HANDLE`] type may be transferred across and shared between
81
102
// thread boundaries (despite containing a `*mut void`, which in general isn't
82
103
// `Send` or `Sync`).
83
104
//
84
105
// [`HANDLE`]: std::os::windows::raw::HANDLE
85
106
unsafe impl Send for OwnedHandle { }
107
+ unsafe impl Send for HandleOrNull { }
86
108
unsafe impl Send for HandleOrInvalid { }
87
109
unsafe impl Send for BorrowedHandle < ' _ > { }
88
110
unsafe impl Sync for OwnedHandle { }
111
+ unsafe impl Sync for HandleOrNull { }
89
112
unsafe impl Sync for HandleOrInvalid { }
90
113
unsafe impl Sync for BorrowedHandle < ' _ > { }
91
114
@@ -95,18 +118,29 @@ impl BorrowedHandle<'_> {
95
118
/// # Safety
96
119
///
97
120
/// 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`.
100
122
///
101
123
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
102
124
/// sometimes a valid handle value. See [here] for the full story.
103
125
///
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
+ ///
104
129
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
105
130
#[ inline]
106
131
#[ unstable( feature = "io_safety" , issue = "87074" ) ]
107
132
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) }
110
144
}
111
145
}
112
146
@@ -115,44 +149,29 @@ impl TryFrom<HandleOrInvalid> for OwnedHandle {
115
149
116
150
#[ inline]
117
151
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) }
135
154
}
136
155
}
137
156
138
157
impl AsRawHandle for BorrowedHandle < ' _ > {
139
158
#[ inline]
140
159
fn as_raw_handle ( & self ) -> RawHandle {
141
- self . handle . as_ptr ( )
160
+ self . handle
142
161
}
143
162
}
144
163
145
164
impl AsRawHandle for OwnedHandle {
146
165
#[ inline]
147
166
fn as_raw_handle ( & self ) -> RawHandle {
148
- self . handle . as_ptr ( )
167
+ self . handle
149
168
}
150
169
}
151
170
152
171
impl IntoRawHandle for OwnedHandle {
153
172
#[ inline]
154
173
fn into_raw_handle ( self ) -> RawHandle {
155
- let handle = self . handle . as_ptr ( ) ;
174
+ let handle = self . handle ;
156
175
forget ( self ) ;
157
176
handle
158
177
}
@@ -161,9 +180,6 @@ impl IntoRawHandle for OwnedHandle {
161
180
impl FromRawHandle for OwnedHandle {
162
181
/// Constructs a new instance of `Self` from the given raw handle.
163
182
///
164
- /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
165
- /// use `INVALID_HANDLE_VALUE` to indicate failure.
166
- ///
167
183
/// # Safety
168
184
///
169
185
/// The resource pointed to by `handle` must be open and suitable for
@@ -180,8 +196,28 @@ impl FromRawHandle for OwnedHandle {
180
196
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
181
197
#[ inline]
182
198
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) )
185
221
}
186
222
}
187
223
@@ -190,29 +226,28 @@ impl FromRawHandle for HandleOrInvalid {
190
226
/// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
191
227
/// failure, such as `CreateFileW`.
192
228
///
193
- /// Use `Option<OwnedHandle> ` instead of `HandleOrInvalid` for APIs that
229
+ /// Use `HandleOrNull ` instead of `HandleOrInvalid` for APIs that
194
230
/// use null to indicate failure.
195
231
///
196
232
/// # Safety
197
233
///
198
234
/// 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.
202
238
///
203
239
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
204
240
#[ inline]
205
241
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) )
208
243
}
209
244
}
210
245
211
246
impl Drop for OwnedHandle {
212
247
#[ inline]
213
248
fn drop ( & mut self ) {
214
249
unsafe {
215
- let _ = c:: CloseHandle ( self . handle . as_ptr ( ) ) ;
250
+ let _ = c:: CloseHandle ( self . handle ) ;
216
251
}
217
252
}
218
253
}
0 commit comments