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