Skip to content

Commit 599b092

Browse files
committed
Avoid closing invalid handles
1 parent 3ad8e2d commit 599b092

File tree

1 file changed

+35
-37
lines changed

1 file changed

+35
-37
lines changed

library/std/src/os/windows/io/handle.rs

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::fs;
88
use crate::io;
99
use crate::marker::PhantomData;
1010
use crate::mem::forget;
11+
use crate::mem::ManuallyDrop;
1112
use crate::ptr;
1213
use crate::sys;
1314
use crate::sys::cvt;
@@ -91,7 +92,7 @@ pub struct OwnedHandle {
9192
#[repr(transparent)]
9293
#[stable(feature = "io_safety", since = "1.63.0")]
9394
#[derive(Debug)]
94-
pub struct HandleOrNull(OwnedHandle);
95+
pub struct HandleOrNull(ManuallyDrop<OwnedHandle>);
9596

9697
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
9798
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
@@ -110,7 +111,7 @@ pub struct HandleOrNull(OwnedHandle);
110111
#[repr(transparent)]
111112
#[stable(feature = "io_safety", since = "1.63.0")]
112113
#[derive(Debug)]
113-
pub struct HandleOrInvalid(OwnedHandle);
114+
pub struct HandleOrInvalid(ManuallyDrop<OwnedHandle>);
114115

115116
// The Windows [`HANDLE`] type may be transferred across and shared between
116117
// thread boundaries (despite containing a `*mut void`, which in general isn't
@@ -157,24 +158,40 @@ impl BorrowedHandle<'_> {
157158
}
158159
}
159160

160-
#[stable(feature = "io_safety", since = "1.63.0")]
161-
impl TryFrom<HandleOrNull> for OwnedHandle {
162-
type Error = NullHandleError;
161+
macro_rules! impl_handle_or {
162+
( $name:ident, $invalid_handle:expr, $error:ident ) => {
163+
impl $name {
164+
unsafe fn take_owned_handle(&mut self) -> Option<OwnedHandle> {
165+
// Filter before taking the value, to avoid calling `Drop` on the invalid value.
166+
Some(&mut self.0)
167+
.filter(|handle| handle.handle != $invalid_handle)
168+
.map(|handle| unsafe { ManuallyDrop::take(handle) })
169+
}
170+
}
163171

164-
#[inline]
165-
fn try_from(handle_or_null: HandleOrNull) -> Result<Self, NullHandleError> {
166-
let owned_handle = handle_or_null.0;
167-
if owned_handle.handle.is_null() {
168-
// Don't call `CloseHandle`; it'd be harmless, except that it could
169-
// overwrite the `GetLastError` error.
170-
forget(owned_handle);
172+
#[stable(feature = "io_safety", since = "1.63.0")]
173+
impl TryFrom<$name> for OwnedHandle {
174+
type Error = $error;
171175

172-
Err(NullHandleError(()))
173-
} else {
174-
Ok(owned_handle)
176+
#[inline]
177+
fn try_from(handle_or: $name) -> Result<Self, $error> {
178+
// SAFETY: `ManuallyDrop` prevents calling `Drop`.
179+
unsafe { ManuallyDrop::new(handle_or).take_owned_handle() }.ok_or($error(()))
180+
}
175181
}
176-
}
182+
183+
#[stable(feature = "handle_or_drop", since = "1.75.0")]
184+
impl Drop for $name {
185+
#[inline]
186+
fn drop(&mut self) {
187+
// SAFETY: `Drop` has already been called (and is running).
188+
let _ = unsafe { self.take_owned_handle() };
189+
}
190+
}
191+
};
177192
}
193+
impl_handle_or!(HandleOrNull, ptr::null_mut(), NullHandleError);
194+
impl_handle_or!(HandleOrInvalid, sys::c::INVALID_HANDLE_VALUE, InvalidHandleError);
178195

179196
impl OwnedHandle {
180197
/// Creates a new `OwnedHandle` instance that shares the same underlying
@@ -226,25 +243,6 @@ impl BorrowedHandle<'_> {
226243
}
227244
}
228245

229-
#[stable(feature = "io_safety", since = "1.63.0")]
230-
impl TryFrom<HandleOrInvalid> for OwnedHandle {
231-
type Error = InvalidHandleError;
232-
233-
#[inline]
234-
fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, InvalidHandleError> {
235-
let owned_handle = handle_or_invalid.0;
236-
if owned_handle.handle == sys::c::INVALID_HANDLE_VALUE {
237-
// Don't call `CloseHandle`; it'd be harmless, except that it could
238-
// overwrite the `GetLastError` error.
239-
forget(owned_handle);
240-
241-
Err(InvalidHandleError(()))
242-
} else {
243-
Ok(owned_handle)
244-
}
245-
}
246-
}
247-
248246
/// This is the error type used by [`HandleOrNull`] when attempting to convert
249247
/// into a handle, to indicate that the value is null.
250248
// The empty field prevents constructing this, and allows extending it in the future.
@@ -333,7 +331,7 @@ impl HandleOrNull {
333331
#[stable(feature = "io_safety", since = "1.63.0")]
334332
#[inline]
335333
pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
336-
Self(OwnedHandle::from_raw_handle(handle))
334+
Self(ManuallyDrop::new(OwnedHandle::from_raw_handle(handle)))
337335
}
338336
}
339337

@@ -356,7 +354,7 @@ impl HandleOrInvalid {
356354
#[stable(feature = "io_safety", since = "1.63.0")]
357355
#[inline]
358356
pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
359-
Self(OwnedHandle::from_raw_handle(handle))
357+
Self(ManuallyDrop::new(OwnedHandle::from_raw_handle(handle)))
360358
}
361359
}
362360

0 commit comments

Comments
 (0)