Skip to content

Commit aeae332

Browse files
authored
Rollup merge of rust-lang#127763 - ChrisDenton:safe-unsafe-unsafe, r=tgross35
Make more Windows functions `#![deny(unsafe_op_in_unsafe_fn)]` As part of rust-lang#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
2 parents f431b51 + 417b61f commit aeae332

File tree

10 files changed

+111
-90
lines changed

10 files changed

+111
-90
lines changed

std/src/sys/os_str/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![forbid(unsafe_op_in_unsafe_fn)]
2+
13
cfg_if::cfg_if! {
24
if #[cfg(any(
35
target_os = "windows",

std/src/sys/os_str/wtf8.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! The underlying OsString/OsStr implementation on Windows is a
22
//! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
3-
43
use crate::borrow::Cow;
54
use crate::collections::TryReserveError;
65
use crate::fmt;
@@ -71,7 +70,7 @@ impl Buf {
7170

7271
#[inline]
7372
pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self {
74-
Self { inner: Wtf8Buf::from_bytes_unchecked(s) }
73+
unsafe { Self { inner: Wtf8Buf::from_bytes_unchecked(s) } }
7574
}
7675

7776
pub fn with_capacity(capacity: usize) -> Buf {
@@ -190,7 +189,7 @@ impl Slice {
190189

191190
#[inline]
192191
pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice {
193-
mem::transmute(Wtf8::from_bytes_unchecked(s))
192+
unsafe { mem::transmute(Wtf8::from_bytes_unchecked(s)) }
194193
}
195194

196195
#[track_caller]

std/src/sys/pal/windows/alloc.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![deny(unsafe_op_in_unsafe_fn)]
2-
31
use crate::alloc::{GlobalAlloc, Layout, System};
42
use crate::ffi::c_void;
53
use crate::ptr;

std/src/sys/pal/windows/fs.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#![allow(unsafe_op_in_unsafe_fn)]
21
use core::ptr::addr_of;
32

43
use crate::os::windows::prelude::*;
@@ -795,10 +794,12 @@ impl<'a> Iterator for DirBuffIter<'a> {
795794
}
796795

797796
unsafe fn from_maybe_unaligned<'a>(p: *const u16, len: usize) -> Cow<'a, [u16]> {
798-
if p.is_aligned() {
799-
Cow::Borrowed(crate::slice::from_raw_parts(p, len))
800-
} else {
801-
Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect())
797+
unsafe {
798+
if p.is_aligned() {
799+
Cow::Borrowed(crate::slice::from_raw_parts(p, len))
800+
} else {
801+
Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect())
802+
}
802803
}
803804
}
804805

@@ -897,7 +898,9 @@ impl IntoRawHandle for File {
897898

898899
impl FromRawHandle for File {
899900
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
900-
Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) }
901+
unsafe {
902+
Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) }
903+
}
901904
}
902905
}
903906

@@ -1427,10 +1430,12 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
14271430
_hDestinationFile: c::HANDLE,
14281431
lpData: *const c_void,
14291432
) -> u32 {
1430-
if dwStreamNumber == 1 {
1431-
*(lpData as *mut i64) = StreamBytesTransferred;
1433+
unsafe {
1434+
if dwStreamNumber == 1 {
1435+
*(lpData as *mut i64) = StreamBytesTransferred;
1436+
}
1437+
c::PROGRESS_CONTINUE
14321438
}
1433-
c::PROGRESS_CONTINUE
14341439
}
14351440
let pfrom = maybe_verbatim(from)?;
14361441
let pto = maybe_verbatim(to)?;

std/src/sys/pal/windows/handle.rs

+33-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![unstable(issue = "none", feature = "windows_handle")]
2-
#![allow(unsafe_op_in_unsafe_fn)]
32

43
#[cfg(test)]
54
mod tests;
@@ -73,7 +72,7 @@ impl IntoRawHandle for Handle {
7372

7473
impl FromRawHandle for Handle {
7574
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
76-
Self(FromRawHandle::from_raw_handle(raw_handle))
75+
unsafe { Self(FromRawHandle::from_raw_handle(raw_handle)) }
7776
}
7877
}
7978

@@ -139,13 +138,23 @@ impl Handle {
139138

140139
pub unsafe fn read_overlapped(
141140
&self,
142-
buf: &mut [u8],
141+
buf: &mut [mem::MaybeUninit<u8>],
143142
overlapped: *mut c::OVERLAPPED,
144143
) -> io::Result<Option<usize>> {
145-
let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
146-
let mut amt = 0;
147-
let res =
148-
cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped));
144+
// SAFETY: We have exclusive access to the buffer and it's up to the caller to
145+
// ensure the OVERLAPPED pointer is valid for the lifetime of this function.
146+
let (res, amt) = unsafe {
147+
let len = cmp::min(buf.len(), u32::MAX as usize) as u32;
148+
let mut amt = 0;
149+
let res = cvt(c::ReadFile(
150+
self.as_raw_handle(),
151+
buf.as_mut_ptr().cast::<u8>(),
152+
len,
153+
&mut amt,
154+
overlapped,
155+
));
156+
(res, amt)
157+
};
149158
match res {
150159
Ok(_) => Ok(Some(amt as usize)),
151160
Err(e) => {
@@ -230,20 +239,24 @@ impl Handle {
230239

231240
// The length is clamped at u32::MAX.
232241
let len = cmp::min(len, u32::MAX as usize) as u32;
233-
let status = c::NtReadFile(
234-
self.as_handle(),
235-
ptr::null_mut(),
236-
None,
237-
ptr::null_mut(),
238-
&mut io_status,
239-
buf,
240-
len,
241-
offset.map(|n| n as _).as_ref(),
242-
None,
243-
);
242+
// SAFETY: It's up to the caller to ensure `buf` is writeable up to
243+
// the provided `len`.
244+
let status = unsafe {
245+
c::NtReadFile(
246+
self.as_handle(),
247+
ptr::null_mut(),
248+
None,
249+
ptr::null_mut(),
250+
&mut io_status,
251+
buf,
252+
len,
253+
offset.map(|n| n as _).as_ref(),
254+
None,
255+
)
256+
};
244257

245258
let status = if status == c::STATUS_PENDING {
246-
c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE);
259+
unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) };
247260
io_status.status()
248261
} else {
249262
status
@@ -261,7 +274,7 @@ impl Handle {
261274
status if c::nt_success(status) => Ok(io_status.Information),
262275

263276
status => {
264-
let error = c::RtlNtStatusToDosError(status);
277+
let error = unsafe { c::RtlNtStatusToDosError(status) };
265278
Err(io::Error::from_raw_os_error(error as _))
266279
}
267280
}

std/src/sys/pal/windows/io.rs

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#![allow(unsafe_op_in_unsafe_fn)]
21
use crate::marker::PhantomData;
32
use crate::mem::size_of;
43
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
@@ -81,19 +80,17 @@ impl<'a> IoSliceMut<'a> {
8180
}
8281

8382
pub fn is_terminal(h: &impl AsHandle) -> bool {
84-
unsafe { handle_is_console(h.as_handle()) }
83+
handle_is_console(h.as_handle())
8584
}
8685

87-
unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool {
88-
let handle = handle.as_raw_handle();
89-
86+
fn handle_is_console(handle: BorrowedHandle<'_>) -> bool {
9087
// A null handle means the process has no console.
91-
if handle.is_null() {
88+
if handle.as_raw_handle().is_null() {
9289
return false;
9390
}
9491

9592
let mut out = 0;
96-
if c::GetConsoleMode(handle, &mut out) != 0 {
93+
if unsafe { c::GetConsoleMode(handle.as_raw_handle(), &mut out) != 0 } {
9794
// False positives aren't possible. If we got a console then we definitely have a console.
9895
return true;
9996
}
@@ -102,9 +99,9 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool {
10299
msys_tty_on(handle)
103100
}
104101

105-
unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
102+
fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool {
106103
// Early return if the handle is not a pipe.
107-
if c::GetFileType(handle) != c::FILE_TYPE_PIPE {
104+
if unsafe { c::GetFileType(handle.as_raw_handle()) != c::FILE_TYPE_PIPE } {
108105
return false;
109106
}
110107

@@ -120,12 +117,14 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
120117
}
121118
let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] };
122119
// Safety: buffer length is fixed.
123-
let res = c::GetFileInformationByHandleEx(
124-
handle,
125-
c::FileNameInfo,
126-
core::ptr::addr_of_mut!(name_info) as *mut c_void,
127-
size_of::<FILE_NAME_INFO>() as u32,
128-
);
120+
let res = unsafe {
121+
c::GetFileInformationByHandleEx(
122+
handle.as_raw_handle(),
123+
c::FileNameInfo,
124+
core::ptr::addr_of_mut!(name_info) as *mut c_void,
125+
size_of::<FILE_NAME_INFO>() as u32,
126+
)
127+
};
129128
if res == 0 {
130129
return false;
131130
}

std/src/sys/pal/windows/os.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Implementation of `std::os` functionality for Windows.
22
33
#![allow(nonstandard_style)]
4-
#![allow(unsafe_op_in_unsafe_fn)]
54

65
#[cfg(test)]
76
mod tests;
@@ -305,15 +304,21 @@ pub fn getenv(k: &OsStr) -> Option<OsString> {
305304
}
306305

307306
pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
308-
let k = to_u16s(k)?;
309-
let v = to_u16s(v)?;
307+
// SAFETY: We ensure that k and v are null-terminated wide strings.
308+
unsafe {
309+
let k = to_u16s(k)?;
310+
let v = to_u16s(v)?;
310311

311-
cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop)
312+
cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop)
313+
}
312314
}
313315

314316
pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> {
315-
let v = to_u16s(n)?;
316-
cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop)
317+
// SAFETY: We ensure that v is a null-terminated wide strings.
318+
unsafe {
319+
let v = to_u16s(n)?;
320+
cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop)
321+
}
317322
}
318323

319324
pub fn temp_dir() -> PathBuf {

std/src/sys/pal/windows/pipe.rs

+6-14
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
#![allow(unsafe_op_in_unsafe_fn)]
21
use crate::os::windows::prelude::*;
32

43
use crate::ffi::OsStr;
54
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
65
use crate::mem;
76
use crate::path::Path;
87
use crate::ptr;
9-
use crate::slice;
108
use crate::sync::atomic::AtomicUsize;
119
use crate::sync::atomic::Ordering::Relaxed;
1210
use crate::sys::c;
@@ -325,6 +323,7 @@ impl AnonPipe {
325323
/// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex
326324
/// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex
327325
/// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls
326+
#[allow(unsafe_op_in_unsafe_fn)]
328327
unsafe fn alertable_io_internal(
329328
&self,
330329
io: AlertableIoFn,
@@ -479,8 +478,11 @@ impl<'a> AsyncPipe<'a> {
479478
fn schedule_read(&mut self) -> io::Result<bool> {
480479
assert_eq!(self.state, State::NotReading);
481480
let amt = unsafe {
482-
let slice = slice_to_end(self.dst);
483-
self.pipe.read_overlapped(slice, &mut *self.overlapped)?
481+
if self.dst.capacity() == self.dst.len() {
482+
let additional = if self.dst.capacity() == 0 { 16 } else { 1 };
483+
self.dst.reserve(additional);
484+
}
485+
self.pipe.read_overlapped(self.dst.spare_capacity_mut(), &mut *self.overlapped)?
484486
};
485487

486488
// If this read finished immediately then our overlapped event will
@@ -560,13 +562,3 @@ impl<'a> Drop for AsyncPipe<'a> {
560562
}
561563
}
562564
}
563-
564-
unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
565-
if v.capacity() == 0 {
566-
v.reserve(16);
567-
}
568-
if v.capacity() == v.len() {
569-
v.reserve(1);
570-
}
571-
slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len())
572-
}
+11-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
#![cfg_attr(test, allow(dead_code))]
2-
#![allow(unsafe_op_in_unsafe_fn)]
32

43
use crate::sys::c;
54
use crate::thread;
65

76
/// Reserve stack space for use in stack overflow exceptions.
8-
pub unsafe fn reserve_stack() {
9-
let result = c::SetThreadStackGuarantee(&mut 0x5000);
7+
pub fn reserve_stack() {
8+
let result = unsafe { c::SetThreadStackGuarantee(&mut 0x5000) };
109
// Reserving stack space is not critical so we allow it to fail in the released build of libstd.
1110
// We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
1211
debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
1312
}
1413

1514
unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 {
15+
// SAFETY: It's up to the caller (which in this case is the OS) to ensure that `ExceptionInfo` is valid.
1616
unsafe {
1717
let rec = &(*(*ExceptionInfo).ExceptionRecord);
1818
let code = rec.ExceptionCode;
@@ -27,11 +27,14 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN
2727
}
2828
}
2929

30-
pub unsafe fn init() {
31-
let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
32-
// Similar to the above, adding the stack overflow handler is allowed to fail
33-
// but a debug assert is used so CI will still test that it normally works.
34-
debug_assert!(!result.is_null(), "failed to install exception handler");
30+
pub fn init() {
31+
// SAFETY: `vectored_handler` has the correct ABI and is safe to call during exception handling.
32+
unsafe {
33+
let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
34+
// Similar to the above, adding the stack overflow handler is allowed to fail
35+
// but a debug assert is used so CI will still test that it normally works.
36+
debug_assert!(!result.is_null(), "failed to install exception handler");
37+
}
3538
// Set the thread stack guarantee for the main thread.
3639
reserve_stack();
3740
}

0 commit comments

Comments
 (0)