Skip to content

Commit ed08061

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

File tree

1 file changed

+36
-37
lines changed

1 file changed

+36
-37
lines changed

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

Lines changed: 36 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,41 @@ 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
166+
// the invalid value.
167+
Some(&mut self.0)
168+
.filter(|handle| handle.handle != $invalid_handle)
169+
.map(|handle| unsafe { ManuallyDrop::take(handle) })
170+
}
171+
}
163172

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);
173+
#[stable(feature = "io_safety", since = "1.63.0")]
174+
impl TryFrom<$name> for OwnedHandle {
175+
type Error = $error;
171176

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

179197
impl OwnedHandle {
180198
/// Creates a new `OwnedHandle` instance that shares the same underlying
@@ -226,25 +244,6 @@ impl BorrowedHandle<'_> {
226244
}
227245
}
228246

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-
248247
/// This is the error type used by [`HandleOrNull`] when attempting to convert
249248
/// into a handle, to indicate that the value is null.
250249
// The empty field prevents constructing this, and allows extending it in the future.
@@ -333,7 +332,7 @@ impl HandleOrNull {
333332
#[stable(feature = "io_safety", since = "1.63.0")]
334333
#[inline]
335334
pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
336-
Self(OwnedHandle::from_raw_handle(handle))
335+
Self(ManuallyDrop::new(OwnedHandle::from_raw_handle(handle)))
337336
}
338337
}
339338

@@ -356,7 +355,7 @@ impl HandleOrInvalid {
356355
#[stable(feature = "io_safety", since = "1.63.0")]
357356
#[inline]
358357
pub unsafe fn from_raw_handle(handle: RawHandle) -> Self {
359-
Self(OwnedHandle::from_raw_handle(handle))
358+
Self(ManuallyDrop::new(OwnedHandle::from_raw_handle(handle)))
360359
}
361360
}
362361

0 commit comments

Comments
 (0)