Rollup merge of #127763 - ChrisDenton:safe-unsafe-unsafe, r=tgross35
Make more Windows functions `#![deny(unsafe_op_in_unsafe_fn)]` As part of #127747, I've evaluated some more Windows functions and added `unsafe` blocks where necessary. Some are just trivial wrappers that "inherit" the full unsafety of their function, but for others I've added some safety comments. A few functions weren't actually unsafe at all. I think they were just using `unsafe fn` to avoid an `unsafe {}` block. I'm not touching `c.rs` yet because that is partially being addressed by another PR and also I have plans to further reduce the number of wrapper functions we have in there. r? libs
This commit is contained in:
commit
56f95559da
@ -1,3 +1,5 @@
|
|||||||
|
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(any(
|
if #[cfg(any(
|
||||||
target_os = "windows",
|
target_os = "windows",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! The underlying OsString/OsStr implementation on Windows is a
|
//! The underlying OsString/OsStr implementation on Windows is a
|
||||||
//! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
|
//! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
|
||||||
|
|
||||||
use crate::borrow::Cow;
|
use crate::borrow::Cow;
|
||||||
use crate::collections::TryReserveError;
|
use crate::collections::TryReserveError;
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
@ -71,7 +70,7 @@ pub fn into_encoded_bytes(self) -> Vec<u8> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self {
|
pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self {
|
||||||
Self { inner: Wtf8Buf::from_bytes_unchecked(s) }
|
unsafe { Self { inner: Wtf8Buf::from_bytes_unchecked(s) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_capacity(capacity: usize) -> Buf {
|
pub fn with_capacity(capacity: usize) -> Buf {
|
||||||
@ -190,7 +189,7 @@ pub fn as_encoded_bytes(&self) -> &[u8] {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice {
|
pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice {
|
||||||
mem::transmute(Wtf8::from_bytes_unchecked(s))
|
unsafe { mem::transmute(Wtf8::from_bytes_unchecked(s)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
|
||||||
|
|
||||||
use crate::alloc::{GlobalAlloc, Layout, System};
|
use crate::alloc::{GlobalAlloc, Layout, System};
|
||||||
use crate::ffi::c_void;
|
use crate::ffi::c_void;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
use core::ptr::addr_of;
|
use core::ptr::addr_of;
|
||||||
|
|
||||||
use crate::os::windows::prelude::*;
|
use crate::os::windows::prelude::*;
|
||||||
@ -795,10 +794,12 @@ fn next(&mut self) -> Option<Self::Item> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn from_maybe_unaligned<'a>(p: *const u16, len: usize) -> Cow<'a, [u16]> {
|
unsafe fn from_maybe_unaligned<'a>(p: *const u16, len: usize) -> Cow<'a, [u16]> {
|
||||||
if p.is_aligned() {
|
unsafe {
|
||||||
Cow::Borrowed(crate::slice::from_raw_parts(p, len))
|
if p.is_aligned() {
|
||||||
} else {
|
Cow::Borrowed(crate::slice::from_raw_parts(p, len))
|
||||||
Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect())
|
} else {
|
||||||
|
Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,7 +898,9 @@ fn into_raw_handle(self) -> RawHandle {
|
|||||||
|
|
||||||
impl FromRawHandle for File {
|
impl FromRawHandle for File {
|
||||||
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
|
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
|
||||||
Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) }
|
unsafe {
|
||||||
|
Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1427,10 +1430,12 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
|
|||||||
_hDestinationFile: c::HANDLE,
|
_hDestinationFile: c::HANDLE,
|
||||||
lpData: *const c_void,
|
lpData: *const c_void,
|
||||||
) -> u32 {
|
) -> u32 {
|
||||||
if dwStreamNumber == 1 {
|
unsafe {
|
||||||
*(lpData as *mut i64) = StreamBytesTransferred;
|
if dwStreamNumber == 1 {
|
||||||
|
*(lpData as *mut i64) = StreamBytesTransferred;
|
||||||
|
}
|
||||||
|
c::PROGRESS_CONTINUE
|
||||||
}
|
}
|
||||||
c::PROGRESS_CONTINUE
|
|
||||||
}
|
}
|
||||||
let pfrom = maybe_verbatim(from)?;
|
let pfrom = maybe_verbatim(from)?;
|
||||||
let pto = maybe_verbatim(to)?;
|
let pto = maybe_verbatim(to)?;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#![unstable(issue = "none", feature = "windows_handle")]
|
#![unstable(issue = "none", feature = "windows_handle")]
|
||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -73,7 +72,7 @@ fn into_raw_handle(self) -> RawHandle {
|
|||||||
|
|
||||||
impl FromRawHandle for Handle {
|
impl FromRawHandle for Handle {
|
||||||
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
|
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
|
||||||
Self(FromRawHandle::from_raw_handle(raw_handle))
|
unsafe { Self(FromRawHandle::from_raw_handle(raw_handle)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,13 +138,23 @@ pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
|||||||
|
|
||||||
pub unsafe fn read_overlapped(
|
pub unsafe fn read_overlapped(
|
||||||
&self,
|
&self,
|
||||||
buf: &mut [u8],
|
buf: &mut [mem::MaybeUninit<u8>],
|
||||||
overlapped: *mut c::OVERLAPPED,
|
overlapped: *mut c::OVERLAPPED,
|
||||||
) -> io::Result<Option<usize>> {
|
) -> io::Result<Option<usize>> {
|
||||||
let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
|
// SAFETY: We have exclusive access to the buffer and it's up to the caller to
|
||||||
let mut amt = 0;
|
// ensure the OVERLAPPED pointer is valid for the lifetime of this function.
|
||||||
let res =
|
let (res, amt) = unsafe {
|
||||||
cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped));
|
let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
|
||||||
|
let mut amt = 0;
|
||||||
|
let res = cvt(c::ReadFile(
|
||||||
|
self.as_raw_handle(),
|
||||||
|
buf.as_mut_ptr().cast::<u8>(),
|
||||||
|
len,
|
||||||
|
&mut amt,
|
||||||
|
overlapped,
|
||||||
|
));
|
||||||
|
(res, amt)
|
||||||
|
};
|
||||||
match res {
|
match res {
|
||||||
Ok(_) => Ok(Some(amt as usize)),
|
Ok(_) => Ok(Some(amt as usize)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -230,20 +239,24 @@ unsafe fn synchronous_read(
|
|||||||
|
|
||||||
// The length is clamped at u32::MAX.
|
// The length is clamped at u32::MAX.
|
||||||
let len = cmp::min(len, u32::MAX as usize) as u32;
|
let len = cmp::min(len, u32::MAX as usize) as u32;
|
||||||
let status = c::NtReadFile(
|
// SAFETY: It's up to the caller to ensure `buf` is writeable up to
|
||||||
self.as_handle(),
|
// the provided `len`.
|
||||||
ptr::null_mut(),
|
let status = unsafe {
|
||||||
None,
|
c::NtReadFile(
|
||||||
ptr::null_mut(),
|
self.as_handle(),
|
||||||
&mut io_status,
|
ptr::null_mut(),
|
||||||
buf,
|
None,
|
||||||
len,
|
ptr::null_mut(),
|
||||||
offset.map(|n| n as _).as_ref(),
|
&mut io_status,
|
||||||
None,
|
buf,
|
||||||
);
|
len,
|
||||||
|
offset.map(|n| n as _).as_ref(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let status = if status == c::STATUS_PENDING {
|
let status = if status == c::STATUS_PENDING {
|
||||||
c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE);
|
unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) };
|
||||||
io_status.status()
|
io_status.status()
|
||||||
} else {
|
} else {
|
||||||
status
|
status
|
||||||
@ -261,7 +274,7 @@ unsafe fn synchronous_read(
|
|||||||
status if c::nt_success(status) => Ok(io_status.Information),
|
status if c::nt_success(status) => Ok(io_status.Information),
|
||||||
|
|
||||||
status => {
|
status => {
|
||||||
let error = c::RtlNtStatusToDosError(status);
|
let error = unsafe { c::RtlNtStatusToDosError(status) };
|
||||||
Err(io::Error::from_raw_os_error(error as _))
|
Err(io::Error::from_raw_os_error(error as _))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
use crate::marker::PhantomData;
|
use crate::marker::PhantomData;
|
||||||
use crate::mem::size_of;
|
use crate::mem::size_of;
|
||||||
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
|
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
|
||||||
@ -81,19 +80,17 @@ pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_terminal(h: &impl AsHandle) -> bool {
|
pub fn is_terminal(h: &impl AsHandle) -> bool {
|
||||||
unsafe { handle_is_console(h.as_handle()) }
|
handle_is_console(h.as_handle())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool {
|
fn handle_is_console(handle: BorrowedHandle<'_>) -> bool {
|
||||||
let handle = handle.as_raw_handle();
|
|
||||||
|
|
||||||
// A null handle means the process has no console.
|
// A null handle means the process has no console.
|
||||||
if handle.is_null() {
|
if handle.as_raw_handle().is_null() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut out = 0;
|
let mut out = 0;
|
||||||
if c::GetConsoleMode(handle, &mut out) != 0 {
|
if unsafe { c::GetConsoleMode(handle.as_raw_handle(), &mut out) != 0 } {
|
||||||
// False positives aren't possible. If we got a console then we definitely have a console.
|
// False positives aren't possible. If we got a console then we definitely have a console.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -102,9 +99,9 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool {
|
|||||||
msys_tty_on(handle)
|
msys_tty_on(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
|
fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool {
|
||||||
// Early return if the handle is not a pipe.
|
// Early return if the handle is not a pipe.
|
||||||
if c::GetFileType(handle) != c::FILE_TYPE_PIPE {
|
if unsafe { c::GetFileType(handle.as_raw_handle()) != c::FILE_TYPE_PIPE } {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +117,14 @@ struct FILE_NAME_INFO {
|
|||||||
}
|
}
|
||||||
let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] };
|
let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] };
|
||||||
// Safety: buffer length is fixed.
|
// Safety: buffer length is fixed.
|
||||||
let res = c::GetFileInformationByHandleEx(
|
let res = unsafe {
|
||||||
handle,
|
c::GetFileInformationByHandleEx(
|
||||||
c::FileNameInfo,
|
handle.as_raw_handle(),
|
||||||
core::ptr::addr_of_mut!(name_info) as *mut c_void,
|
c::FileNameInfo,
|
||||||
size_of::<FILE_NAME_INFO>() as u32,
|
core::ptr::addr_of_mut!(name_info) as *mut c_void,
|
||||||
);
|
size_of::<FILE_NAME_INFO>() as u32,
|
||||||
|
)
|
||||||
|
};
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//! Implementation of `std::os` functionality for Windows.
|
//! Implementation of `std::os` functionality for Windows.
|
||||||
|
|
||||||
#![allow(nonstandard_style)]
|
#![allow(nonstandard_style)]
|
||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -305,15 +304,21 @@ pub fn getenv(k: &OsStr) -> Option<OsString> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
|
pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
|
||||||
let k = to_u16s(k)?;
|
// SAFETY: We ensure that k and v are null-terminated wide strings.
|
||||||
let v = to_u16s(v)?;
|
unsafe {
|
||||||
|
let k = to_u16s(k)?;
|
||||||
|
let v = to_u16s(v)?;
|
||||||
|
|
||||||
cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop)
|
cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> {
|
pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> {
|
||||||
let v = to_u16s(n)?;
|
// SAFETY: We ensure that v is a null-terminated wide strings.
|
||||||
cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop)
|
unsafe {
|
||||||
|
let v = to_u16s(n)?;
|
||||||
|
cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn temp_dir() -> PathBuf {
|
pub fn temp_dir() -> PathBuf {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
use crate::os::windows::prelude::*;
|
use crate::os::windows::prelude::*;
|
||||||
|
|
||||||
use crate::ffi::OsStr;
|
use crate::ffi::OsStr;
|
||||||
@ -6,7 +5,6 @@
|
|||||||
use crate::mem;
|
use crate::mem;
|
||||||
use crate::path::Path;
|
use crate::path::Path;
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
use crate::slice;
|
|
||||||
use crate::sync::atomic::AtomicUsize;
|
use crate::sync::atomic::AtomicUsize;
|
||||||
use crate::sync::atomic::Ordering::Relaxed;
|
use crate::sync::atomic::Ordering::Relaxed;
|
||||||
use crate::sys::c;
|
use crate::sys::c;
|
||||||
@ -325,6 +323,7 @@ pub fn is_write_vectored(&self) -> bool {
|
|||||||
/// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex
|
/// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex
|
||||||
/// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex
|
/// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex
|
||||||
/// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
|
/// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
|
||||||
|
#[allow(unsafe_op_in_unsafe_fn)]
|
||||||
unsafe fn alertable_io_internal(
|
unsafe fn alertable_io_internal(
|
||||||
&self,
|
&self,
|
||||||
io: AlertableIoFn,
|
io: AlertableIoFn,
|
||||||
@ -479,8 +478,11 @@ fn new(pipe: Handle, dst: &'a mut Vec<u8>) -> io::Result<AsyncPipe<'a>> {
|
|||||||
fn schedule_read(&mut self) -> io::Result<bool> {
|
fn schedule_read(&mut self) -> io::Result<bool> {
|
||||||
assert_eq!(self.state, State::NotReading);
|
assert_eq!(self.state, State::NotReading);
|
||||||
let amt = unsafe {
|
let amt = unsafe {
|
||||||
let slice = slice_to_end(self.dst);
|
if self.dst.capacity() == self.dst.len() {
|
||||||
self.pipe.read_overlapped(slice, &mut *self.overlapped)?
|
let additional = if self.dst.capacity() == 0 { 16 } else { 1 };
|
||||||
|
self.dst.reserve(additional);
|
||||||
|
}
|
||||||
|
self.pipe.read_overlapped(self.dst.spare_capacity_mut(), &mut *self.overlapped)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// If this read finished immediately then our overlapped event will
|
// If this read finished immediately then our overlapped event will
|
||||||
@ -560,13 +562,3 @@ fn drop(&mut self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
|
|
||||||
if v.capacity() == 0 {
|
|
||||||
v.reserve(16);
|
|
||||||
}
|
|
||||||
if v.capacity() == v.len() {
|
|
||||||
v.reserve(1);
|
|
||||||
}
|
|
||||||
slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len())
|
|
||||||
}
|
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
#![cfg_attr(test, allow(dead_code))]
|
#![cfg_attr(test, allow(dead_code))]
|
||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
|
|
||||||
use crate::sys::c;
|
use crate::sys::c;
|
||||||
use crate::thread;
|
use crate::thread;
|
||||||
|
|
||||||
/// Reserve stack space for use in stack overflow exceptions.
|
/// Reserve stack space for use in stack overflow exceptions.
|
||||||
pub unsafe fn reserve_stack() {
|
pub fn reserve_stack() {
|
||||||
let result = c::SetThreadStackGuarantee(&mut 0x5000);
|
let result = unsafe { c::SetThreadStackGuarantee(&mut 0x5000) };
|
||||||
// Reserving stack space is not critical so we allow it to fail in the released build of libstd.
|
// Reserving stack space is not critical so we allow it to fail in the released build of libstd.
|
||||||
// We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
|
// We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
|
||||||
debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
|
debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 {
|
unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 {
|
||||||
|
// SAFETY: It's up to the caller (which in this case is the OS) to ensure that `ExceptionInfo` is valid.
|
||||||
unsafe {
|
unsafe {
|
||||||
let rec = &(*(*ExceptionInfo).ExceptionRecord);
|
let rec = &(*(*ExceptionInfo).ExceptionRecord);
|
||||||
let code = rec.ExceptionCode;
|
let code = rec.ExceptionCode;
|
||||||
@ -27,11 +27,14 @@ pub unsafe fn reserve_stack() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn init() {
|
pub fn init() {
|
||||||
let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
|
// SAFETY: `vectored_handler` has the correct ABI and is safe to call during exception handling.
|
||||||
// Similar to the above, adding the stack overflow handler is allowed to fail
|
unsafe {
|
||||||
// but a debug assert is used so CI will still test that it normally works.
|
let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
|
||||||
debug_assert!(!result.is_null(), "failed to install exception handler");
|
// Similar to the above, adding the stack overflow handler is allowed to fail
|
||||||
|
// but a debug assert is used so CI will still test that it normally works.
|
||||||
|
debug_assert!(!result.is_null(), "failed to install exception handler");
|
||||||
|
}
|
||||||
// Set the thread stack guarantee for the main thread.
|
// Set the thread stack guarantee for the main thread.
|
||||||
reserve_stack();
|
reserve_stack();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
use crate::ffi::CStr;
|
use crate::ffi::CStr;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::num::NonZero;
|
use crate::num::NonZero;
|
||||||
@ -28,21 +27,25 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
|||||||
|
|
||||||
// CreateThread rounds up values for the stack size to the nearest page size (at least 4kb).
|
// CreateThread rounds up values for the stack size to the nearest page size (at least 4kb).
|
||||||
// If a value of zero is given then the default stack size is used instead.
|
// If a value of zero is given then the default stack size is used instead.
|
||||||
let ret = c::CreateThread(
|
// SAFETY: `thread_start` has the right ABI for a thread's entry point.
|
||||||
ptr::null_mut(),
|
// `p` is simply passed through to the new thread without being touched.
|
||||||
stack,
|
let ret = unsafe {
|
||||||
Some(thread_start),
|
let ret = c::CreateThread(
|
||||||
p as *mut _,
|
ptr::null_mut(),
|
||||||
c::STACK_SIZE_PARAM_IS_A_RESERVATION,
|
stack,
|
||||||
ptr::null_mut(),
|
Some(thread_start),
|
||||||
);
|
p as *mut _,
|
||||||
let ret = HandleOrNull::from_raw_handle(ret);
|
c::STACK_SIZE_PARAM_IS_A_RESERVATION,
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
|
HandleOrNull::from_raw_handle(ret)
|
||||||
|
};
|
||||||
return if let Ok(handle) = ret.try_into() {
|
return if let Ok(handle) = ret.try_into() {
|
||||||
Ok(Thread { handle: Handle::from_inner(handle) })
|
Ok(Thread { handle: Handle::from_inner(handle) })
|
||||||
} else {
|
} else {
|
||||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||||
// safe to reconstruct the box so that it gets deallocated.
|
// safe to reconstruct the box so that it gets deallocated.
|
||||||
drop(Box::from_raw(p));
|
unsafe { drop(Box::from_raw(p)) };
|
||||||
Err(io::Error::last_os_error())
|
Err(io::Error::last_os_error())
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -50,7 +53,9 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
|||||||
// Next, reserve some stack space for if we otherwise run out of stack.
|
// Next, reserve some stack space for if we otherwise run out of stack.
|
||||||
stack_overflow::reserve_stack();
|
stack_overflow::reserve_stack();
|
||||||
// Finally, let's run some code.
|
// Finally, let's run some code.
|
||||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
// SAFETY: We are simply recreating the box that was leaked earlier.
|
||||||
|
// It's the responsibility of the one who call `Thread::new` to ensure this is safe to call here.
|
||||||
|
unsafe { Box::from_raw(main as *mut Box<dyn FnOnce()>)() };
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +75,7 @@ pub fn set_name(name: &CStr) {
|
|||||||
///
|
///
|
||||||
/// `name` must end with a zero value
|
/// `name` must end with a zero value
|
||||||
pub unsafe fn set_name_wide(name: &[u16]) {
|
pub unsafe fn set_name_wide(name: &[u16]) {
|
||||||
c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr());
|
unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join(self) {
|
pub fn join(self) {
|
||||||
|
Loading…
Reference in New Issue
Block a user