From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- library/std/src/os/windows/io/handle.rs | 576 ++++++++++++++++++++++++++++++++ library/std/src/os/windows/io/mod.rs | 65 ++++ library/std/src/os/windows/io/raw.rs | 305 +++++++++++++++++ library/std/src/os/windows/io/socket.rs | 338 +++++++++++++++++++ library/std/src/os/windows/io/tests.rs | 21 ++ 5 files changed, 1305 insertions(+) create mode 100644 library/std/src/os/windows/io/handle.rs create mode 100644 library/std/src/os/windows/io/mod.rs create mode 100644 library/std/src/os/windows/io/raw.rs create mode 100644 library/std/src/os/windows/io/socket.rs create mode 100644 library/std/src/os/windows/io/tests.rs (limited to 'library/std/src/os/windows/io') diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs new file mode 100644 index 000000000..16cc8fa27 --- /dev/null +++ b/library/std/src/os/windows/io/handle.rs @@ -0,0 +1,576 @@ +//! Owned and borrowed OS handles. + +#![stable(feature = "io_safety", since = "1.63.0")] + +use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; +use crate::fmt; +use crate::fs; +use crate::io; +use crate::marker::PhantomData; +use crate::mem::forget; +use crate::ptr; +use crate::sys::c; +use crate::sys::cvt; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// A borrowed handle. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the handle. +/// +/// This uses `repr(transparent)` and has the representation of a host handle, +/// so it can be used in FFI in places where a handle is passed as an argument, +/// it is not captured or consumed. +/// +/// Note that it *may* have the value `-1`, which in `BorrowedHandle` always +/// represents a valid handle value, such as [the current process handle], and +/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See +/// [here] for the full story. +/// +/// And, it *may* have the value `NULL` (0), which can occur when consoles are +/// detached from processes, or when `windows_subsystem` is used. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedHandle` +/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw +/// handle, which is then borrowed under the same lifetime. +/// +/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks +#[derive(Copy, Clone)] +#[repr(transparent)] +#[stable(feature = "io_safety", since = "1.63.0")] +pub struct BorrowedHandle<'handle> { + handle: RawHandle, + _phantom: PhantomData<&'handle OwnedHandle>, +} + +/// An owned handle. +/// +/// This closes the handle on drop. +/// +/// Note that it *may* have the value `-1`, which in `OwnedHandle` always +/// represents a valid handle value, such as [the current process handle], and +/// not `INVALID_HANDLE_VALUE`, despite the two having the same value. See +/// [here] for the full story. +/// +/// And, it *may* have the value `NULL` (0), which can occur when consoles are +/// detached from processes, or when `windows_subsystem` is used. +/// +/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such, +/// it must not be used with handles to open registry keys which need to be +/// closed with [`RegCloseKey`] instead. +/// +/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle +/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey +/// +/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks +#[repr(transparent)] +#[stable(feature = "io_safety", since = "1.63.0")] +pub struct OwnedHandle { + handle: RawHandle, +} + +/// FFI type for handles in return values or out parameters, where `NULL` is used +/// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses +/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such +/// FFI declarations. +/// +/// The only thing you can usefully do with a `HandleOrNull` is to convert it into an +/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for +/// `NULL`. This ensures that such FFI calls cannot start using the handle without +/// checking for `NULL` first. +/// +/// This type may hold any handle value that [`OwnedHandle`] may hold. As with `OwnedHandle`, when +/// it holds `-1`, that value is interpreted as a valid handle value, such as +/// [the current process handle], and not `INVALID_HANDLE_VALUE`. +/// +/// If this holds a non-null handle, it will close the handle on drop. +/// +/// [the current process handle]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess#remarks +#[repr(transparent)] +#[stable(feature = "io_safety", since = "1.63.0")] +#[derive(Debug)] +pub struct HandleOrNull(OwnedHandle); + +/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used +/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses +/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such +/// FFI declarations. +/// +/// The only thing you can usefully do with a `HandleOrInvalid` is to convert it into an +/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for +/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without +/// checking for `INVALID_HANDLE_VALUE` first. +/// +/// This type may hold any handle value that [`OwnedHandle`] may hold, except that when it holds +/// `-1`, that value is interpreted to mean `INVALID_HANDLE_VALUE`. +/// +/// If holds a handle other than `INVALID_HANDLE_VALUE`, it will close the handle on drop. +#[repr(transparent)] +#[stable(feature = "io_safety", since = "1.63.0")] +#[derive(Debug)] +pub struct HandleOrInvalid(OwnedHandle); + +// The Windows [`HANDLE`] type may be transferred across and shared between +// thread boundaries (despite containing a `*mut void`, which in general isn't +// `Send` or `Sync`). +// +// [`HANDLE`]: std::os::windows::raw::HANDLE +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Send for OwnedHandle {} +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Send for HandleOrNull {} +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Send for HandleOrInvalid {} +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Send for BorrowedHandle<'_> {} +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Sync for OwnedHandle {} +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Sync for HandleOrNull {} +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Sync for HandleOrInvalid {} +#[stable(feature = "io_safety", since = "1.63.0")] +unsafe impl Sync for BorrowedHandle<'_> {} + +impl BorrowedHandle<'_> { + /// Return a `BorrowedHandle` holding the given raw handle. + /// + /// # Safety + /// + /// The resource pointed to by `handle` must be a valid open handle, it + /// must remain open for the duration of the returned `BorrowedHandle`. + /// + /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is + /// sometimes a valid handle value. See [here] for the full story. + /// + /// And, it *may* have the value `NULL` (0), which can occur when consoles are + /// detached from processes, or when `windows_subsystem` is used. + /// + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + #[inline] + #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] + #[stable(feature = "io_safety", since = "1.63.0")] + pub const unsafe fn borrow_raw(handle: RawHandle) -> Self { + Self { handle, _phantom: PhantomData } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl TryFrom for OwnedHandle { + type Error = NullHandleError; + + #[inline] + fn try_from(handle_or_null: HandleOrNull) -> Result { + let owned_handle = handle_or_null.0; + if owned_handle.handle.is_null() { + // Don't call `CloseHandle`; it'd be harmless, except that it could + // overwrite the `GetLastError` error. + forget(owned_handle); + + Err(NullHandleError(())) + } else { + Ok(owned_handle) + } + } +} + +impl OwnedHandle { + /// Creates a new `OwnedHandle` instance that shares the same underlying + /// object as the existing `OwnedHandle` instance. + #[stable(feature = "io_safety", since = "1.63.0")] + pub fn try_clone(&self) -> crate::io::Result { + self.as_handle().try_clone_to_owned() + } +} + +impl BorrowedHandle<'_> { + /// Creates a new `OwnedHandle` instance that shares the same underlying + /// object as the existing `BorrowedHandle` instance. + #[stable(feature = "io_safety", since = "1.63.0")] + pub fn try_clone_to_owned(&self) -> crate::io::Result { + self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS) + } + + pub(crate) fn duplicate( + &self, + access: c::DWORD, + inherit: bool, + options: c::DWORD, + ) -> io::Result { + let handle = self.as_raw_handle(); + + // `Stdin`, `Stdout`, and `Stderr` can all hold null handles, such as + // in a process with a detached console. `DuplicateHandle` would fail + // if we passed it a null handle, but we can treat null as a valid + // handle which doesn't do any I/O, and allow it to be duplicated. + if handle.is_null() { + return unsafe { Ok(OwnedHandle::from_raw_handle(handle)) }; + } + + let mut ret = ptr::null_mut(); + cvt(unsafe { + let cur_proc = c::GetCurrentProcess(); + c::DuplicateHandle( + cur_proc, + handle, + cur_proc, + &mut ret, + access, + inherit as c::BOOL, + options, + ) + })?; + unsafe { Ok(OwnedHandle::from_raw_handle(ret)) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl TryFrom for OwnedHandle { + type Error = InvalidHandleError; + + #[inline] + fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { + let owned_handle = handle_or_invalid.0; + if owned_handle.handle == c::INVALID_HANDLE_VALUE { + // Don't call `CloseHandle`; it'd be harmless, except that it could + // overwrite the `GetLastError` error. + forget(owned_handle); + + Err(InvalidHandleError(())) + } else { + Ok(owned_handle) + } + } +} + +/// This is the error type used by [`HandleOrNull`] when attempting to convert +/// into a handle, to indicate that the value is null. +// The empty field prevents constructing this, and allows extending it in the future. +#[stable(feature = "io_safety", since = "1.63.0")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NullHandleError(()); + +#[stable(feature = "io_safety", since = "1.63.0")] +impl fmt::Display for NullHandleError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl crate::error::Error for NullHandleError {} + +/// This is the error type used by [`HandleOrInvalid`] when attempting to +/// convert into a handle, to indicate that the value is +/// `INVALID_HANDLE_VALUE`. +// The empty field prevents constructing this, and allows extending it in the future. +#[stable(feature = "io_safety", since = "1.63.0")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvalidHandleError(()); + +#[stable(feature = "io_safety", since = "1.63.0")] +impl fmt::Display for InvalidHandleError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE" + .fmt(fmt) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl crate::error::Error for InvalidHandleError {} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsRawHandle for BorrowedHandle<'_> { + #[inline] + fn as_raw_handle(&self) -> RawHandle { + self.handle + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsRawHandle for OwnedHandle { + #[inline] + fn as_raw_handle(&self) -> RawHandle { + self.handle + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl IntoRawHandle for OwnedHandle { + #[inline] + fn into_raw_handle(self) -> RawHandle { + let handle = self.handle; + forget(self); + handle + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl FromRawHandle for OwnedHandle { + #[inline] + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + Self { handle } + } +} + +impl HandleOrNull { + /// Constructs a new instance of `Self` from the given `RawHandle` returned + /// from a Windows API that uses null to indicate failure, such as + /// `CreateThread`. + /// + /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that + /// use `INVALID_HANDLE_VALUE` to indicate failure. + /// + /// # Safety + /// + /// The passed `handle` value must either satisfy the safety requirements + /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all + /// Windows APIs use null for errors; see [here] for the full story. + /// + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + #[stable(feature = "io_safety", since = "1.63.0")] + #[inline] + pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { + Self(OwnedHandle::from_raw_handle(handle)) + } +} + +impl HandleOrInvalid { + /// Constructs a new instance of `Self` from the given `RawHandle` returned + /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate + /// failure, such as `CreateFileW`. + /// + /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that + /// use null to indicate failure. + /// + /// # Safety + /// + /// The passed `handle` value must either satisfy the safety requirements + /// of [`FromRawHandle::from_raw_handle`], or be + /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use + /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story. + /// + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + #[stable(feature = "io_safety", since = "1.63.0")] + #[inline] + pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { + Self(OwnedHandle::from_raw_handle(handle)) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl Drop for OwnedHandle { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::CloseHandle(self.handle); + } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl fmt::Debug for BorrowedHandle<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedHandle").field("handle", &self.handle).finish() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl fmt::Debug for OwnedHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedHandle").field("handle", &self.handle).finish() + } +} + +/// A trait to borrow the handle from an underlying object. +#[stable(feature = "io_safety", since = "1.63.0")] +pub trait AsHandle { + /// Borrows the handle. + /// + /// # Example + /// + /// ```rust,no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::windows::io::{AsHandle, BorrowedHandle}; + /// + /// let mut f = File::open("foo.txt")?; + /// let borrowed_handle: BorrowedHandle<'_> = f.as_handle(); + /// # Ok::<(), io::Error>(()) + /// ``` + #[stable(feature = "io_safety", since = "1.63.0")] + fn as_handle(&self) -> BorrowedHandle<'_>; +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for &T { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + T::as_handle(self) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for &mut T { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + T::as_handle(self) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for BorrowedHandle<'_> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + *self + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for OwnedHandle { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity + // invariants, and the `BorrowdHandle` is bounded by the lifetime + // of `&self`. + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for fs::File { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().as_handle() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedHandle { + #[inline] + fn from(file: fs::File) -> OwnedHandle { + file.into_inner().into_inner().into_inner().into() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for fs::File { + #[inline] + fn from(owned: OwnedHandle) -> Self { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for crate::io::Stdin { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl<'a> AsHandle for crate::io::StdinLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for crate::io::Stdout { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl<'a> AsHandle for crate::io::StdoutLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for crate::io::Stderr { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl<'a> AsHandle for crate::io::StderrLock<'a> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for crate::process::ChildStdin { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedHandle { + #[inline] + fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for crate::process::ChildStdout { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedHandle { + #[inline] + fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for crate::process::ChildStderr { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedHandle { + #[inline] + fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle { + unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsHandle for crate::thread::JoinHandle { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From> for OwnedHandle { + #[inline] + fn from(join_handle: crate::thread::JoinHandle) -> OwnedHandle { + join_handle.into_inner().into_handle().into_inner() + } +} diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs new file mode 100644 index 000000000..e2a401fb6 --- /dev/null +++ b/library/std/src/os/windows/io/mod.rs @@ -0,0 +1,65 @@ +//! Windows-specific extensions to general I/O primitives. +//! +//! Just like raw pointers, raw Windows handles and sockets point to resources +//! with dynamic lifetimes, and they can dangle if they outlive their resources +//! or be forged if they're created from invalid values. +//! +//! This module provides three types for representing raw handles and sockets +//! with different ownership properties: raw, borrowed, and owned, which are +//! analogous to types used for representing pointers: +//! +//! | Type | Analogous to | +//! | ---------------------- | ------------ | +//! | [`RawHandle`] | `*const _` | +//! | [`RawSocket`] | `*const _` | +//! | | | +//! | [`BorrowedHandle<'a>`] | `&'a _` | +//! | [`BorrowedSocket<'a>`] | `&'a _` | +//! | | | +//! | [`OwnedHandle`] | `Box<_>` | +//! | [`OwnedSocket`] | `Box<_>` | +//! +//! Like raw pointers, `RawHandle` and `RawSocket` values are primitive values. +//! And in new code, they should be considered unsafe to do I/O on (analogous +//! to dereferencing them). Rust did not always provide this guidance, so +//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and +//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable, +//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs +//! that dereference `RawHandle` and `RawSocket` values, or by using to +//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`. +//! +//! Like references, `BorrowedHandle` and `BorrowedSocket` values are tied to a +//! lifetime, to ensure that they don't outlive the resource they point to. +//! These are safe to use. `BorrowedHandle` and `BorrowedSocket` values may be +//! used in APIs which provide safe access to any system call except for +//! `CloseHandle`, `closesocket`, or any other call that would end the +//! dynamic lifetime of the resource without ending the lifetime of the +//! handle or socket. +//! +//! `BorrowedHandle` and `BorrowedSocket` values may be used in APIs which +//! provide safe access to `DuplicateHandle` and `WSADuplicateSocketW` and +//! related functions, so types implementing `AsHandle`, `AsSocket`, +//! `From`, or `From` should not assume they always +//! have exclusive access to the underlying object. +//! +//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the +//! resource they point to, and free (close) it when they are dropped. +//! +//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle +//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket + +#![stable(feature = "rust1", since = "1.0.0")] + +mod handle; +mod raw; +mod socket; + +#[stable(feature = "io_safety", since = "1.63.0")] +pub use handle::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::*; +#[stable(feature = "io_safety", since = "1.63.0")] +pub use socket::*; + +#[cfg(test)] +mod tests; diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs new file mode 100644 index 000000000..49e4f304f --- /dev/null +++ b/library/std/src/os/windows/io/raw.rs @@ -0,0 +1,305 @@ +//! Windows-specific extensions to general I/O primitives. + +#![stable(feature = "rust1", since = "1.0.0")] + +use crate::fs; +use crate::io; +use crate::net; +#[cfg(doc)] +use crate::os::windows::io::{AsHandle, AsSocket}; +use crate::os::windows::io::{OwnedHandle, OwnedSocket}; +use crate::os::windows::raw; +use crate::ptr; +use crate::sys; +use crate::sys::c; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; + +/// Raw HANDLEs. +#[stable(feature = "rust1", since = "1.0.0")] +pub type RawHandle = raw::HANDLE; + +/// Raw SOCKETs. +#[stable(feature = "rust1", since = "1.0.0")] +pub type RawSocket = raw::SOCKET; + +/// Extracts raw handles. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawHandle { + /// Extracts the raw handle. + /// + /// This function is typically used to **borrow** an owned handle. + /// When used in this way, this method does **not** pass ownership of the + /// raw handle to the caller, and the handle is only guaranteed + /// to be valid while the original object has not yet been destroyed. + /// + /// This function may return null, such as when called on [`Stdin`], + /// [`Stdout`], or [`Stderr`] when the console is detached. + /// + /// However, borrowing is not strictly required. See [`AsHandle::as_handle`] + /// for an API which strictly borrows a handle. + /// + /// [`Stdin`]: io::Stdin + /// [`Stdout`]: io::Stdout + /// [`Stderr`]: io::Stderr + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_handle(&self) -> RawHandle; +} + +/// Construct I/O objects from raw handles. +#[stable(feature = "from_raw_os", since = "1.1.0")] +pub trait FromRawHandle { + /// Constructs a new I/O object from the specified raw handle. + /// + /// This function is typically used to **consume ownership** of the handle + /// given, passing responsibility for closing the handle to the returned + /// object. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// `From::from` implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety + /// + /// The `handle` passed in must: + /// - be a valid an open handle, + /// - be a handle for a resource that may be freed via [`CloseHandle`] + /// (as opposed to `RegCloseKey` or other close functions). + /// + /// Note that the handle *may* have the value `INVALID_HANDLE_VALUE` (-1), + /// which is sometimes a valid handle value. See [here] for the full story. + /// + /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 + #[stable(feature = "from_raw_os", since = "1.1.0")] + unsafe fn from_raw_handle(handle: RawHandle) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `HANDLE`. +#[stable(feature = "into_raw_os", since = "1.4.0")] +pub trait IntoRawHandle { + /// Consumes this object, returning the raw underlying handle. + /// + /// This function is typically used to **transfer ownership** of the underlying + /// handle to the caller. When used in this way, callers are then the unique + /// owners of the handle and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// `Into::into` implementation for an API which strictly + /// transfers ownership. + #[stable(feature = "into_raw_os", since = "1.4.0")] + fn into_raw_handle(self) -> RawHandle; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawHandle for fs::File { + #[inline] + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().as_raw_handle() as RawHandle + } +} + +#[stable(feature = "asraw_stdio", since = "1.21.0")] +impl AsRawHandle for io::Stdin { + fn as_raw_handle(&self) -> RawHandle { + stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }) + } +} + +#[stable(feature = "asraw_stdio", since = "1.21.0")] +impl AsRawHandle for io::Stdout { + fn as_raw_handle(&self) -> RawHandle { + stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }) + } +} + +#[stable(feature = "asraw_stdio", since = "1.21.0")] +impl AsRawHandle for io::Stderr { + fn as_raw_handle(&self) -> RawHandle { + stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }) + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StdinLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + stdio_handle(unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }) + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StdoutLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + stdio_handle(unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }) + } +} + +#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +impl<'a> AsRawHandle for io::StderrLock<'a> { + fn as_raw_handle(&self) -> RawHandle { + stdio_handle(unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }) + } +} + +// Translate a handle returned from `GetStdHandle` into a handle to return to +// the user. +fn stdio_handle(raw: RawHandle) -> RawHandle { + // `GetStdHandle` isn't expected to actually fail, so when it returns + // `INVALID_HANDLE_VALUE`, it means we were launched from a parent which + // didn't provide us with stdio handles, such as a parent with a detached + // console. In that case, return null to the user, which is consistent + // with what they'd get in the parent, and which avoids the problem that + // `INVALID_HANDLE_VALUE` aliases the current process handle. + if raw == c::INVALID_HANDLE_VALUE { ptr::null_mut() } else { raw } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawHandle for fs::File { + #[inline] + unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { + let handle = handle as c::HANDLE; + fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawHandle for fs::File { + #[inline] + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_raw_handle() as *mut _ + } +} + +/// Extracts raw sockets. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait AsRawSocket { + /// Extracts the raw socket. + /// + /// This function is typically used to **borrow** an owned socket. + /// When used in this way, this method does **not** pass ownership of the + /// raw socket to the caller, and the socket is only guaranteed + /// to be valid while the original object has not yet been destroyed. + /// + /// However, borrowing is not strictly required. See [`AsSocket::as_socket`] + /// for an API which strictly borrows a socket. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_raw_socket(&self) -> RawSocket; +} + +/// Creates I/O objects from raw sockets. +#[stable(feature = "from_raw_os", since = "1.1.0")] +pub trait FromRawSocket { + /// Constructs a new I/O object from the specified raw socket. + /// + /// This function is typically used to **consume ownership** of the socket + /// given, passing responsibility for closing the socket to the returned + /// object. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// `From::from` implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety + /// + /// The `socket` passed in must: + /// - be a valid an open socket, + /// - be a socket that may be freed via [`closesocket`]. + /// + /// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket + #[stable(feature = "from_raw_os", since = "1.1.0")] + unsafe fn from_raw_socket(sock: RawSocket) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `SOCKET`. +#[stable(feature = "into_raw_os", since = "1.4.0")] +pub trait IntoRawSocket { + /// Consumes this object, returning the raw underlying socket. + /// + /// This function is typically used to **transfer ownership** of the underlying + /// socket to the caller. When used in this way, callers are then the unique + /// owners of the socket and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// `Into::into` implementation for an API which strictly + /// transfers ownership. + #[stable(feature = "into_raw_os", since = "1.4.0")] + fn into_raw_socket(self) -> RawSocket; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::TcpStream { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.as_inner().socket().as_raw_socket() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::TcpListener { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.as_inner().socket().as_raw_socket() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawSocket for net::UdpSocket { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.as_inner().socket().as_raw_socket() + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawSocket for net::TcpStream { + #[inline] + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock)) + } +} +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawSocket for net::TcpListener { + #[inline] + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock)) + } +} +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawSocket for net::UdpSocket { + #[inline] + unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { + let sock = sys::net::Socket::from_inner(OwnedSocket::from_raw_socket(sock)); + net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawSocket for net::TcpStream { + #[inline] + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner().into_raw_socket() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawSocket for net::TcpListener { + #[inline] + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner().into_raw_socket() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawSocket for net::UdpSocket { + #[inline] + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner().into_raw_socket() + } +} diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs new file mode 100644 index 000000000..72cb3406d --- /dev/null +++ b/library/std/src/os/windows/io/socket.rs @@ -0,0 +1,338 @@ +//! Owned and borrowed OS sockets. + +#![stable(feature = "io_safety", since = "1.63.0")] + +use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; +use crate::fmt; +use crate::io; +use crate::marker::PhantomData; +use crate::mem; +use crate::mem::forget; +use crate::sys; +use crate::sys::c; +#[cfg(not(target_vendor = "uwp"))] +use crate::sys::cvt; + +/// A borrowed socket. +/// +/// This has a lifetime parameter to tie it to the lifetime of something that +/// owns the socket. +/// +/// This uses `repr(transparent)` and has the representation of a host socket, +/// so it can be used in FFI in places where a socket is passed as an argument, +/// it is not captured or consumed, and it never has the value +/// `INVALID_SOCKET`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedSocket` +/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw +/// socket, which is then borrowed under the same lifetime. +#[derive(Copy, Clone)] +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// This is -2, in two's complement. -1 is `INVALID_SOCKET`. +#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr( + target_pointer_width = "64", + rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) +)] +#[rustc_nonnull_optimization_guaranteed] +#[stable(feature = "io_safety", since = "1.63.0")] +pub struct BorrowedSocket<'socket> { + socket: RawSocket, + _phantom: PhantomData<&'socket OwnedSocket>, +} + +/// An owned socket. +/// +/// This closes the socket on drop. +/// +/// This uses `repr(transparent)` and has the representation of a host socket, +/// so it can be used in FFI in places where a socket is passed as a consumed +/// argument or returned as an owned value, and it never has the value +/// `INVALID_SOCKET`. +#[repr(transparent)] +#[rustc_layout_scalar_valid_range_start(0)] +// This is -2, in two's complement. -1 is `INVALID_SOCKET`. +#[cfg_attr(target_pointer_width = "32", rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE))] +#[cfg_attr( + target_pointer_width = "64", + rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FF_FF_FF_FF_FE) +)] +#[rustc_nonnull_optimization_guaranteed] +#[stable(feature = "io_safety", since = "1.63.0")] +pub struct OwnedSocket { + socket: RawSocket, +} + +impl BorrowedSocket<'_> { + /// Return a `BorrowedSocket` holding the given raw socket. + /// + /// # Safety + /// + /// The resource pointed to by `raw` must remain open for the duration of + /// the returned `BorrowedSocket`, and it must not have the value + /// `INVALID_SOCKET`. + #[inline] + #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] + #[stable(feature = "io_safety", since = "1.63.0")] + pub const unsafe fn borrow_raw(socket: RawSocket) -> Self { + assert!(socket != c::INVALID_SOCKET as RawSocket); + Self { socket, _phantom: PhantomData } + } +} + +impl OwnedSocket { + /// Creates a new `OwnedSocket` instance that shares the same underlying + /// object as the existing `OwnedSocket` instance. + #[stable(feature = "io_safety", since = "1.63.0")] + pub fn try_clone(&self) -> io::Result { + self.as_socket().try_clone_to_owned() + } + + // FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-; + #[cfg(not(target_vendor = "uwp"))] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + cvt(unsafe { + c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) + }) + .map(drop) + } + + #[cfg(target_vendor = "uwp")] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP")) + } +} + +impl BorrowedSocket<'_> { + /// Creates a new `OwnedSocket` instance that shares the same underlying + /// object as the existing `BorrowedSocket` instance. + #[stable(feature = "io_safety", since = "1.63.0")] + pub fn try_clone_to_owned(&self) -> io::Result { + let mut info = unsafe { mem::zeroed::() }; + let result = unsafe { + c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) + }; + sys::net::cvt(result)?; + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, + ) + }; + + if socket != c::INVALID_SOCKET { + unsafe { Ok(OwnedSocket::from_raw_socket(socket)) } + } else { + let error = unsafe { c::WSAGetLastError() }; + + if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == c::INVALID_SOCKET { + return Err(last_error()); + } + + unsafe { + let socket = OwnedSocket::from_raw_socket(socket); + socket.set_no_inherit()?; + Ok(socket) + } + } + } +} + +/// Returns the last error from the Windows socket interface. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsRawSocket for BorrowedSocket<'_> { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.socket + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsRawSocket for OwnedSocket { + #[inline] + fn as_raw_socket(&self) -> RawSocket { + self.socket + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl IntoRawSocket for OwnedSocket { + #[inline] + fn into_raw_socket(self) -> RawSocket { + let socket = self.socket; + forget(self); + socket + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl FromRawSocket for OwnedSocket { + #[inline] + unsafe fn from_raw_socket(socket: RawSocket) -> Self { + debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); + Self { socket } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl Drop for OwnedSocket { + #[inline] + fn drop(&mut self) { + unsafe { + let _ = c::closesocket(self.socket); + } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl fmt::Debug for BorrowedSocket<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BorrowedSocket").field("socket", &self.socket).finish() + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl fmt::Debug for OwnedSocket { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedSocket").field("socket", &self.socket).finish() + } +} + +/// A trait to borrow the socket from an underlying object. +#[stable(feature = "io_safety", since = "1.63.0")] +pub trait AsSocket { + /// Borrows the socket. + #[stable(feature = "io_safety", since = "1.63.0")] + fn as_socket(&self) -> BorrowedSocket<'_>; +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsSocket for &T { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + T::as_socket(self) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsSocket for &mut T { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + T::as_socket(self) + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsSocket for BorrowedSocket<'_> { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + *self + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsSocket for OwnedSocket { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity + // invariants, and the `BorrowdSocket` is bounded by the lifetime + // of `&self`. + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsSocket for crate::net::TcpStream { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedSocket { + #[inline] + fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for crate::net::TcpStream { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsSocket for crate::net::TcpListener { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedSocket { + #[inline] + fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for crate::net::TcpListener { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl AsSocket for crate::net::UdpSocket { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for OwnedSocket { + #[inline] + fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket { + unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) } + } +} + +#[stable(feature = "io_safety", since = "1.63.0")] +impl From for crate::net::UdpSocket { + #[inline] + fn from(owned: OwnedSocket) -> Self { + unsafe { Self::from_raw_socket(owned.into_raw_socket()) } + } +} diff --git a/library/std/src/os/windows/io/tests.rs b/library/std/src/os/windows/io/tests.rs new file mode 100644 index 000000000..41734e52e --- /dev/null +++ b/library/std/src/os/windows/io/tests.rs @@ -0,0 +1,21 @@ +#[test] +fn test_niche_optimizations_socket() { + use crate::mem::size_of; + use crate::os::windows::io::{ + BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, + }; + + assert_eq!(size_of::>(), size_of::()); + assert_eq!(size_of::>>(), size_of::(),); + unsafe { + #[cfg(target_pointer_width = "32")] + let (min, max) = (i32::MIN as u32, i32::MAX as u32); + #[cfg(target_pointer_width = "64")] + let (min, max) = (i64::MIN as u64, i64::MAX as u64); + + assert_eq!(OwnedSocket::from_raw_socket(min).into_raw_socket(), min); + assert_eq!(OwnedSocket::from_raw_socket(max).into_raw_socket(), max); + assert_eq!(Some(OwnedSocket::from_raw_socket(min)).unwrap().into_raw_socket(), min); + assert_eq!(Some(OwnedSocket::from_raw_socket(max)).unwrap().into_raw_socket(), max); + } +} -- cgit v1.2.3