std\sys\pal\windows/mod.rs
1#![allow(missing_docs, nonstandard_style)]
2#![forbid(unsafe_op_in_unsafe_fn)]
3
4use crate::ffi::{OsStr, OsString};
5use crate::io;
6use crate::mem::MaybeUninit;
7use crate::os::windows::ffi::{OsStrExt, OsStringExt};
8use crate::path::PathBuf;
9use crate::sys::pal::windows::api::wide_str;
10use crate::time::Duration;
11
12#[macro_use]
13pub mod compat;
14
15pub mod api;
16
17pub mod c;
18#[cfg(not(target_vendor = "win7"))]
19pub mod futex;
20pub mod handle;
21pub mod time;
22cfg_select! {
23 // We don't care about printing nice error messages for panic=immediate-abort
24 all(not(target_vendor = "uwp"), not(panic = "immediate-abort")) => {
25 pub mod stack_overflow;
26 }
27 _ => {
28 pub mod stack_overflow_uwp;
29 pub use self::stack_overflow_uwp as stack_overflow;
30 }
31}
32pub mod winsock;
33
34/// Map a [`Result<T, WinError>`] to [`io::Result<T>`].
35pub trait IoResult<T> {
36 fn io_result(self) -> io::Result<T>;
37}
38impl<T> IoResult<T> for Result<T, api::WinError> {
39 fn io_result(self) -> io::Result<T> {
40 self.map_err(|e| io::Error::from_raw_os_error(e.code as i32))
41 }
42}
43
44// SAFETY: must be called only once during runtime initialization.
45// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
46pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
47 unsafe {
48 stack_overflow::init();
49
50 // Normally, `thread::spawn` will call `set_name` but since this thread already
51 // exists, we have to call it ourselves.
52 crate::sys::thread::set_name_wide(wide_str!("main"));
53 }
54}
55
56// SAFETY: must be called only once during runtime cleanup.
57// NOTE: this is not guaranteed to run, for example when the program aborts.
58pub unsafe fn cleanup() {
59 winsock::cleanup();
60}
61
62pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
63 let ptr = haystack.as_ptr();
64 let mut start = haystack;
65
66 // For performance reasons unfold the loop eight times.
67 while start.len() >= 8 {
68 macro_rules! if_return {
69 ($($n:literal,)+) => {
70 $(
71 if start[$n] == needle {
72 return Some(((&start[$n] as *const u16).addr() - ptr.addr()) / 2);
73 }
74 )+
75 }
76 }
77
78 if_return!(0, 1, 2, 3, 4, 5, 6, 7,);
79
80 start = &start[8..];
81 }
82
83 for c in start {
84 if *c == needle {
85 return Some(((c as *const u16).addr() - ptr.addr()) / 2);
86 }
87 }
88 None
89}
90
91pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
92 fn inner(s: &OsStr) -> io::Result<Vec<u16>> {
93 // Most paths are ASCII, so reserve capacity for as much as there are bytes
94 // in the OsStr plus one for the null-terminating character. We are not
95 // wasting bytes here as paths created by this function are primarily used
96 // in an ephemeral fashion.
97 let mut maybe_result = Vec::with_capacity(s.len() + 1);
98 maybe_result.extend(s.encode_wide());
99
100 if unrolled_find_u16s(0, &maybe_result).is_some() {
101 return Err(io::const_error!(
102 io::ErrorKind::InvalidInput,
103 "strings passed to WinAPI cannot contain NULs",
104 ));
105 }
106 maybe_result.push(0);
107 Ok(maybe_result)
108 }
109 inner(s.as_ref())
110}
111
112// Many Windows APIs follow a pattern of where we hand a buffer and then they
113// will report back to us how large the buffer should be or how many bytes
114// currently reside in the buffer. This function is an abstraction over these
115// functions by making them easier to call.
116//
117// The first callback, `f1`, is passed a (pointer, len) pair which can be
118// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
119// The closure is expected to:
120// - On success, return the actual length of the written data *without* the null terminator.
121// This can be 0. In this case the last_error must be left unchanged.
122// - On insufficient buffer space,
123// - either return the required length *with* the null terminator,
124// - or set the last-error to ERROR_INSUFFICIENT_BUFFER and return `len`.
125// - On other failure, return 0 and set last_error.
126//
127// This is how most but not all syscalls indicate the required buffer space.
128// Other syscalls may need translation to match this protocol.
129//
130// Once the syscall has completed (errors bail out early) the second closure is
131// passed the data which has been read from the syscall. The return value
132// from this closure is then the return value of the function.
133pub fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T>
134where
135 F1: FnMut(*mut u16, u32) -> u32,
136 F2: FnOnce(&[u16]) -> T,
137{
138 // Start off with a stack buf but then spill over to the heap if we end up
139 // needing more space.
140 //
141 // This initial size also works around `GetFullPathNameW` returning
142 // incorrect size hints for some short paths:
143 // https://github.com/dylni/normpath/issues/5
144 let mut stack_buf: [MaybeUninit<u16>; 512] = [MaybeUninit::uninit(); 512];
145 let mut heap_buf: Vec<MaybeUninit<u16>> = Vec::new();
146 unsafe {
147 let mut n = stack_buf.len();
148 loop {
149 let buf = if n <= stack_buf.len() {
150 &mut stack_buf[..]
151 } else {
152 let extra = n - heap_buf.len();
153 heap_buf.reserve(extra);
154 // We used `reserve` and not `reserve_exact`, so in theory we
155 // may have gotten more than requested. If so, we'd like to use
156 // it... so long as we won't cause overflow.
157 n = heap_buf.capacity().min(u32::MAX as usize);
158 // Safety: MaybeUninit<u16> does not need initialization
159 heap_buf.set_len(n);
160 &mut heap_buf[..]
161 };
162
163 // This function is typically called on windows API functions which
164 // will return the correct length of the string, but these functions
165 // also return the `0` on error. In some cases, however, the
166 // returned "correct length" may actually be 0!
167 //
168 // To handle this case we call `SetLastError` to reset it to 0 and
169 // then check it again if we get the "0 error value". If the "last
170 // error" is still 0 then we interpret it as a 0 length buffer and
171 // not an actual error.
172 c::SetLastError(0);
173 let k = match f1(buf.as_mut_ptr().cast::<u16>(), n as u32) {
174 0 if api::get_last_error().code == 0 => 0,
175 0 => return Err(io::Error::last_os_error()),
176 n => n,
177 } as usize;
178 if k == n && api::get_last_error().code == c::ERROR_INSUFFICIENT_BUFFER {
179 n = n.saturating_mul(2).min(u32::MAX as usize);
180 } else if k > n {
181 n = k;
182 } else if k == n {
183 // It is impossible to reach this point.
184 // On success, k is the returned string length excluding the null.
185 // On failure, k is the required buffer length including the null.
186 // Therefore k never equals n.
187 unreachable!();
188 } else {
189 // Safety: First `k` values are initialized.
190 let slice: &[u16] = buf[..k].assume_init_ref();
191 return Ok(f2(slice));
192 }
193 }
194 }
195}
196
197pub fn os2path(s: &[u16]) -> PathBuf {
198 PathBuf::from(OsString::from_wide(s))
199}
200
201pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
202 match unrolled_find_u16s(0, v) {
203 // don't include the 0
204 Some(i) => &v[..i],
205 None => v,
206 }
207}
208
209pub fn ensure_no_nuls<T: AsRef<OsStr>>(s: T) -> io::Result<T> {
210 if s.as_ref().encode_wide().any(|b| b == 0) {
211 Err(io::const_error!(io::ErrorKind::InvalidInput, "nul byte found in provided data"))
212 } else {
213 Ok(s)
214 }
215}
216
217pub trait IsZero {
218 fn is_zero(&self) -> bool;
219}
220
221macro_rules! impl_is_zero {
222 ($($t:ident)*) => ($(impl IsZero for $t {
223 fn is_zero(&self) -> bool {
224 *self == 0
225 }
226 })*)
227}
228
229impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
230
231pub fn cvt<I: IsZero>(i: I) -> io::Result<I> {
232 if i.is_zero() { Err(io::Error::last_os_error()) } else { Ok(i) }
233}
234
235#[allow(dead_code)]
236pub fn cvt_nz<I: IsZero>(i: I) -> crate::io::Result<()> {
237 if i.is_zero() { Ok(()) } else { Err(crate::io::Error::last_os_error()) }
238}
239
240pub fn dur2timeout(dur: Duration) -> u32 {
241 // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
242 // timeouts in windows APIs are typically u32 milliseconds. To translate, we
243 // have two pieces to take care of:
244 //
245 // * Nanosecond precision is rounded up
246 // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
247 // (never time out).
248 dur.as_secs()
249 .checked_mul(1000)
250 .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
251 .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
252 .map(|ms| if ms > <u32>::MAX as u64 { c::INFINITE } else { ms as u32 })
253 .unwrap_or(c::INFINITE)
254}
255
256/// Use `__fastfail` to abort the process
257///
258/// In Windows 8 and later, this will terminate the process immediately without
259/// running any in-process exception handlers. In earlier versions of Windows,
260/// this sequence of instructions will be treated as an access violation, which
261/// will still terminate the process but might run some exception handlers.
262///
263/// <https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail>
264#[cfg(not(miri))] // inline assembly does not work in Miri
265pub fn abort_internal() -> ! {
266 unsafe {
267 cfg_select! {
268 any(target_arch = "x86", target_arch = "x86_64") => {
269 core::arch::asm!("int $$0x29", in("ecx") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
270 }
271 all(target_arch = "arm", target_feature = "thumb-mode") => {
272 core::arch::asm!(".inst 0xDEFB", in("r0") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
273 }
274 any(target_arch = "aarch64", target_arch = "arm64ec") => {
275 core::arch::asm!("brk 0xF003", in("x0") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
276 }
277 _ => {
278 core::intrinsics::abort();
279 }
280 }
281 }
282}
283
284#[cfg(miri)]
285#[track_caller] // even without panics, this helps for Miri backtraces
286pub fn abort_internal() -> ! {
287 crate::intrinsics::abort();
288}
289
290/// Align the inner value to 8 bytes.
291///
292/// This is enough for almost all of the buffers we're likely to work with in
293/// the Windows APIs we use.
294#[repr(C, align(8))]
295#[derive(Copy, Clone)]
296pub(crate) struct Align8<T: ?Sized>(pub T);