1use std::ffi::OsStr;
2use std::path::{self, Path, PathBuf};
3use std::{io, iter, str};
4
5use rustc_abi::{Align, Size};
6use rustc_middle::ty::Ty;
7use rustc_span::Symbol;
8use rustc_target::callconv::{Conv, FnAbi};
9
10use self::shims::windows::handle::{Handle, PseudoHandle};
11use crate::shims::os_str::bytes_to_os_str;
12use crate::shims::windows::handle::HandleError;
13use crate::shims::windows::*;
14use crate::*;
15
16const STATUS_INVALID_HANDLE: u32 = 0xD0000008;
19
20pub fn is_dyn_sym(name: &str) -> bool {
21 matches!(
23 name,
24 "SetThreadDescription" | "GetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle"
25 )
26}
27
28#[cfg(windows)]
29fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
30 interp_ok(path::absolute(path))
32}
33
34#[cfg(unix)]
35#[expect(clippy::get_first, clippy::arithmetic_side_effects)]
36fn win_absolute<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
37 let bytes = path.as_os_str().as_encoded_bytes();
39 if bytes.get(0).copied() == Some(b'/') && bytes.get(1).copied() == Some(b'/') {
42 return interp_ok(Ok(path.into()));
43 };
44 let magic_filenames = &[
46 "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8",
47 "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
48 ];
49 if magic_filenames.iter().any(|m| m.as_bytes() == bytes) {
50 let mut result: Vec<u8> = br"//./".into();
51 result.extend(bytes);
52 return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
53 }
54 let mut result = vec![];
58 let mut bytes = bytes; loop {
60 let len = bytes.iter().position(|&b| b == b'/').unwrap_or(bytes.len());
61 let mut component = &bytes[..len];
62 if len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' {
63 component = &component[..len - 1];
65 }
66 result.extend(component);
68 if len < bytes.len() {
70 result.push(b'/');
72 bytes = &bytes[len + 1..];
73 continue;
74 } else {
75 break;
77 }
78 }
79 interp_ok(path::absolute(bytes_to_os_str(&result)?))
81}
82
83impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
84pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
85 fn emulate_foreign_item_inner(
86 &mut self,
87 link_name: Symbol,
88 abi: &FnAbi<'tcx, Ty<'tcx>>,
89 args: &[OpTy<'tcx>],
90 dest: &MPlaceTy<'tcx>,
91 ) -> InterpResult<'tcx, EmulateItemResult> {
92 let this = self.eval_context_mut();
93
94 let sys_conv = if this.tcx.sess.target.arch == "x86" { Conv::X86Stdcall } else { Conv::C };
99
100 match link_name.as_str() {
109 "GetEnvironmentVariableW" => {
111 let [name, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
112 let result = this.GetEnvironmentVariableW(name, buf, size)?;
113 this.write_scalar(result, dest)?;
114 }
115 "SetEnvironmentVariableW" => {
116 let [name, value] = this.check_shim(abi, sys_conv, link_name, args)?;
117 let result = this.SetEnvironmentVariableW(name, value)?;
118 this.write_scalar(result, dest)?;
119 }
120 "GetEnvironmentStringsW" => {
121 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
122 let result = this.GetEnvironmentStringsW()?;
123 this.write_pointer(result, dest)?;
124 }
125 "FreeEnvironmentStringsW" => {
126 let [env_block] = this.check_shim(abi, sys_conv, link_name, args)?;
127 let result = this.FreeEnvironmentStringsW(env_block)?;
128 this.write_scalar(result, dest)?;
129 }
130 "GetCurrentDirectoryW" => {
131 let [size, buf] = this.check_shim(abi, sys_conv, link_name, args)?;
132 let result = this.GetCurrentDirectoryW(size, buf)?;
133 this.write_scalar(result, dest)?;
134 }
135 "SetCurrentDirectoryW" => {
136 let [path] = this.check_shim(abi, sys_conv, link_name, args)?;
137 let result = this.SetCurrentDirectoryW(path)?;
138 this.write_scalar(result, dest)?;
139 }
140 "GetUserProfileDirectoryW" => {
141 let [token, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
142 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
143 this.write_scalar(result, dest)?;
144 }
145 "GetCurrentProcessId" => {
146 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
147 let result = this.GetCurrentProcessId()?;
148 this.write_scalar(result, dest)?;
149 }
150
151 "NtWriteFile" => {
153 if !this.frame_in_std() {
154 throw_unsup_format!(
155 "`NtWriteFile` support is crude and just enough for stdout to work"
156 );
157 }
158
159 let [
160 handle,
161 _event,
162 _apc_routine,
163 _apc_context,
164 io_status_block,
165 buf,
166 n,
167 byte_offset,
168 _key,
169 ] = this.check_shim(abi, sys_conv, link_name, args)?;
170 let handle = this.read_target_isize(handle)?;
171 let buf = this.read_pointer(buf)?;
172 let n = this.read_scalar(n)?.to_u32()?;
173 let byte_offset = this.read_target_usize(byte_offset)?; let io_status_block = this
175 .deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
176
177 if byte_offset != 0 {
178 throw_unsup_format!(
179 "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported"
180 );
181 }
182
183 let written = if handle == -11 || handle == -12 {
184 use io::Write;
186
187 let buf_cont =
188 this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
189 let res = if this.machine.mute_stdout_stderr {
190 Ok(buf_cont.len())
191 } else if handle == -11 {
192 io::stdout().write(buf_cont)
193 } else {
194 io::stderr().write(buf_cont)
195 };
196 res.ok().map(|n| u32::try_from(n).unwrap())
198 } else {
199 throw_unsup_format!(
200 "on Windows, writing to anything except stdout/stderr is not supported"
201 )
202 };
203 if let Some(n) = written {
205 let io_status_information =
206 this.project_field_named(&io_status_block, "Information")?;
207 this.write_scalar(
208 Scalar::from_target_usize(n.into(), this),
209 &io_status_information,
210 )?;
211 }
212 this.write_scalar(
215 Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
216 dest,
217 )?;
218 }
219 "GetFullPathNameW" => {
220 let [filename, size, buffer, filepart] =
221 this.check_shim(abi, sys_conv, link_name, args)?;
222 this.check_no_isolation("`GetFullPathNameW`")?;
223
224 let filename = this.read_pointer(filename)?;
225 let size = this.read_scalar(size)?.to_u32()?;
226 let buffer = this.read_pointer(buffer)?;
227 let filepart = this.read_pointer(filepart)?;
228
229 if !this.ptr_is_null(filepart)? {
230 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
231 }
232
233 let filename = this.read_path_from_wide_str(filename)?;
234 let result = match win_absolute(&filename)? {
235 Err(err) => {
236 this.set_last_error(err)?;
237 Scalar::from_u32(0) }
239 Ok(abs_filename) => {
240 Scalar::from_u32(helpers::windows_check_buffer_size(
241 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
242 ))
243 }
246 };
247 this.write_scalar(result, dest)?;
248 }
249
250 "HeapAlloc" => {
252 let [handle, flags, size] = this.check_shim(abi, sys_conv, link_name, args)?;
253 this.read_target_isize(handle)?;
254 let flags = this.read_scalar(flags)?.to_u32()?;
255 let size = this.read_target_usize(size)?;
256 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
257 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
258 AllocInit::Zero
259 } else {
260 AllocInit::Uninit
261 };
262 let align = this.tcx.pointer_size().bytes().strict_mul(2);
265 let ptr = this.allocate_ptr(
266 Size::from_bytes(size),
267 Align::from_bytes(align).unwrap(),
268 MiriMemoryKind::WinHeap.into(),
269 init,
270 )?;
271 this.write_pointer(ptr, dest)?;
272 }
273 "HeapFree" => {
274 let [handle, flags, ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
275 this.read_target_isize(handle)?;
276 this.read_scalar(flags)?.to_u32()?;
277 let ptr = this.read_pointer(ptr)?;
278 if !this.ptr_is_null(ptr)? {
281 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
282 }
283 this.write_scalar(Scalar::from_i32(1), dest)?;
284 }
285 "HeapReAlloc" => {
286 let [handle, flags, old_ptr, size] =
287 this.check_shim(abi, sys_conv, link_name, args)?;
288 this.read_target_isize(handle)?;
289 this.read_scalar(flags)?.to_u32()?;
290 let old_ptr = this.read_pointer(old_ptr)?;
291 let size = this.read_target_usize(size)?;
292 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
297 old_ptr,
298 None,
299 Size::from_bytes(size),
300 Align::from_bytes(align).unwrap(),
301 MiriMemoryKind::WinHeap.into(),
302 AllocInit::Uninit,
303 )?;
304 this.write_pointer(new_ptr, dest)?;
305 }
306 "LocalFree" => {
307 let [ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
308 let ptr = this.read_pointer(ptr)?;
309 if !this.ptr_is_null(ptr)? {
312 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
313 }
314 this.write_null(dest)?;
315 }
316
317 "SetLastError" => {
319 let [error] = this.check_shim(abi, sys_conv, link_name, args)?;
320 let error = this.read_scalar(error)?;
321 this.set_last_error(error)?;
322 }
323 "GetLastError" => {
324 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
325 let last_error = this.get_last_error()?;
326 this.write_scalar(last_error, dest)?;
327 }
328
329 "GetSystemInfo" => {
331 let [system_info] = this.check_shim(abi, sys_conv, link_name, args)?;
333 let system_info =
334 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
335 this.write_bytes_ptr(
337 system_info.ptr(),
338 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
339 )?;
340 this.write_int_fields_named(
342 &[
343 ("dwPageSize", this.machine.page_size.into()),
344 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
345 ],
346 &system_info,
347 )?;
348 }
349
350 "TlsAlloc" => {
352 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
356 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
357 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
358 }
359 "TlsGetValue" => {
360 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
361 let key = u128::from(this.read_scalar(key)?.to_u32()?);
362 let active_thread = this.active_thread();
363 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
364 this.write_scalar(ptr, dest)?;
365 }
366 "TlsSetValue" => {
367 let [key, new_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
368 let key = u128::from(this.read_scalar(key)?.to_u32()?);
369 let active_thread = this.active_thread();
370 let new_data = this.read_scalar(new_ptr)?;
371 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
372
373 this.write_int(1, dest)?;
375 }
376 "TlsFree" => {
377 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
378 let key = u128::from(this.read_scalar(key)?.to_u32()?);
379 this.machine.tls.delete_tls_key(key)?;
380
381 this.write_int(1, dest)?;
383 }
384
385 "GetCommandLineW" => {
387 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
388 this.write_pointer(
389 this.machine.cmd_line.expect("machine must be initialized"),
390 dest,
391 )?;
392 }
393
394 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
396 #[allow(non_snake_case)]
397 let [LPFILETIME] = this.check_shim(abi, sys_conv, link_name, args)?;
398 this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
399 }
400 "QueryPerformanceCounter" => {
401 #[allow(non_snake_case)]
402 let [lpPerformanceCount] = this.check_shim(abi, sys_conv, link_name, args)?;
403 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
404 this.write_scalar(result, dest)?;
405 }
406 "QueryPerformanceFrequency" => {
407 #[allow(non_snake_case)]
408 let [lpFrequency] = this.check_shim(abi, sys_conv, link_name, args)?;
409 let result = this.QueryPerformanceFrequency(lpFrequency)?;
410 this.write_scalar(result, dest)?;
411 }
412 "Sleep" => {
413 let [timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
414
415 this.Sleep(timeout)?;
416 }
417 "CreateWaitableTimerExW" => {
418 let [attributes, name, flags, access] =
419 this.check_shim(abi, sys_conv, link_name, args)?;
420 this.read_pointer(attributes)?;
421 this.read_pointer(name)?;
422 this.read_scalar(flags)?.to_u32()?;
423 this.read_scalar(access)?.to_u32()?;
424 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
426 this.set_last_error(not_supported)?;
427 this.write_null(dest)?;
428 }
429
430 "InitOnceBeginInitialize" => {
432 let [ptr, flags, pending, context] =
433 this.check_shim(abi, sys_conv, link_name, args)?;
434 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
435 }
436 "InitOnceComplete" => {
437 let [ptr, flags, context] = this.check_shim(abi, sys_conv, link_name, args)?;
438 let result = this.InitOnceComplete(ptr, flags, context)?;
439 this.write_scalar(result, dest)?;
440 }
441 "WaitOnAddress" => {
442 let [ptr_op, compare_op, size_op, timeout_op] =
443 this.check_shim(abi, sys_conv, link_name, args)?;
444
445 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
446 }
447 "WakeByAddressSingle" => {
448 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
449
450 this.WakeByAddressSingle(ptr_op)?;
451 }
452 "WakeByAddressAll" => {
453 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
454
455 this.WakeByAddressAll(ptr_op)?;
456 }
457
458 "GetProcAddress" => {
460 #[allow(non_snake_case)]
461 let [hModule, lpProcName] = this.check_shim(abi, sys_conv, link_name, args)?;
462 this.read_target_isize(hModule)?;
463 let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
464 if let Ok(name) = str::from_utf8(name)
465 && is_dyn_sym(name)
466 {
467 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
468 this.write_pointer(ptr, dest)?;
469 } else {
470 this.write_null(dest)?;
471 }
472 }
473
474 "CreateThread" => {
476 let [security, stacksize, start, arg, flags, thread] =
477 this.check_shim(abi, sys_conv, link_name, args)?;
478
479 let thread_id =
480 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
481
482 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
483 }
484 "WaitForSingleObject" => {
485 let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
486
487 let ret = this.WaitForSingleObject(handle, timeout)?;
488 this.write_scalar(ret, dest)?;
489 }
490 "GetCurrentThread" => {
491 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
492
493 this.write_scalar(
494 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
495 dest,
496 )?;
497 }
498 "SetThreadDescription" => {
499 let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?;
500
501 let handle = this.read_scalar(handle)?;
502 let name = this.read_wide_str(this.read_pointer(name)?)?;
503
504 let thread = match Handle::try_from_scalar(handle, this)? {
505 Ok(Handle::Thread(thread)) => Ok(thread),
506 Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
507 Ok(_) | Err(HandleError::InvalidHandle) =>
508 this.invalid_handle("SetThreadDescription")?,
509 Err(HandleError::ThreadNotFound(e)) => Err(e),
510 };
511 let res = match thread {
512 Ok(thread) => {
513 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
515 Scalar::from_u32(0)
516 }
517 Err(_) => Scalar::from_u32(STATUS_INVALID_HANDLE),
518 };
519
520 this.write_scalar(res, dest)?;
521 }
522 "GetThreadDescription" => {
523 let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
524
525 let handle = this.read_scalar(handle)?;
526 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match Handle::try_from_scalar(handle, this)? {
529 Ok(Handle::Thread(thread)) => Ok(thread),
530 Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => Ok(this.active_thread()),
531 Ok(_) | Err(HandleError::InvalidHandle) =>
532 this.invalid_handle("GetThreadDescription")?,
533 Err(HandleError::ThreadNotFound(e)) => Err(e),
534 };
535 let (name, res) = match thread {
536 Ok(thread) => {
537 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
539 let name = this.alloc_os_str_as_wide_str(
540 bytes_to_os_str(&name)?,
541 MiriMemoryKind::WinLocal.into(),
542 )?;
543 (Scalar::from_maybe_pointer(name, this), Scalar::from_u32(0))
544 }
545 Err(_) => (Scalar::null_ptr(this), Scalar::from_u32(STATUS_INVALID_HANDLE)),
546 };
547
548 this.write_scalar(name, &name_ptr)?;
549 this.write_scalar(res, dest)?;
550 }
551
552 "ExitProcess" => {
554 let [code] = this.check_shim(abi, sys_conv, link_name, args)?;
555 let code = this.read_scalar(code)?.to_i32()?;
557 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
558 }
559 "SystemFunction036" => {
560 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
563 let ptr = this.read_pointer(ptr)?;
564 let len = this.read_scalar(len)?.to_u32()?;
565 this.gen_random(ptr, len.into())?;
566 this.write_scalar(Scalar::from_bool(true), dest)?;
567 }
568 "ProcessPrng" => {
569 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
571 let ptr = this.read_pointer(ptr)?;
572 let len = this.read_target_usize(len)?;
573 this.gen_random(ptr, len)?;
574 this.write_int(1, dest)?;
575 }
576 "BCryptGenRandom" => {
577 let [algorithm, ptr, len, flags] =
579 this.check_shim(abi, sys_conv, link_name, args)?;
580 let algorithm = this.read_scalar(algorithm)?;
581 let algorithm = algorithm.to_target_usize(this)?;
582 let ptr = this.read_pointer(ptr)?;
583 let len = this.read_scalar(len)?.to_u32()?;
584 let flags = this.read_scalar(flags)?.to_u32()?;
585 match flags {
586 0 => {
587 if algorithm != 0x81 {
588 throw_unsup_format!(
590 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
591 );
592 }
593 }
594 2 => {
595 if algorithm != 0 {
597 throw_unsup_format!(
598 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
599 );
600 }
601 }
602 _ => {
603 throw_unsup_format!(
604 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
605 );
606 }
607 }
608 this.gen_random(ptr, len.into())?;
609 this.write_null(dest)?; }
611 "GetConsoleScreenBufferInfo" => {
612 let [console, buffer_info] = this.check_shim(abi, sys_conv, link_name, args)?;
614 this.read_target_isize(console)?;
615 this.deref_pointer(buffer_info)?;
617 this.write_null(dest)?;
620 }
621 "GetStdHandle" => {
622 let [which] = this.check_shim(abi, sys_conv, link_name, args)?;
623 let which = this.read_scalar(which)?.to_i32()?;
624 this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?;
629 }
630 "CloseHandle" => {
631 let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
632
633 let ret = this.CloseHandle(handle)?;
634
635 this.write_scalar(ret, dest)?;
636 }
637 "GetModuleFileNameW" => {
638 let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?;
639 this.check_no_isolation("`GetModuleFileNameW`")?;
640
641 let handle = this.read_target_usize(handle)?;
642 let filename = this.read_pointer(filename)?;
643 let size = this.read_scalar(size)?.to_u32()?;
644
645 if handle != 0 {
646 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
647 }
648
649 let path = std::env::current_exe().unwrap();
652 let (all_written, size_needed) =
653 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
654
655 if all_written {
656 this.write_int(size_needed.strict_sub(1), dest)?;
660 } else {
661 this.write_int(size, dest)?;
666 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
667 this.set_last_error(insufficient_buffer)?;
668 }
669 }
670 "FormatMessageW" => {
671 let [flags, module, message_id, language_id, buffer, size, arguments] =
672 this.check_shim(abi, sys_conv, link_name, args)?;
673
674 let flags = this.read_scalar(flags)?.to_u32()?;
675 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
677 let _language_id = this.read_scalar(language_id)?.to_u32()?;
678 let buffer = this.read_pointer(buffer)?;
679 let size = this.read_scalar(size)?.to_u32()?;
680 let _arguments = this.read_pointer(arguments)?;
681
682 if flags != 4096u32 | 512u32 {
685 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
686 }
687
688 let error = this.try_errnum_to_io_error(message_id)?;
689 let formatted = match error {
690 Some(err) => format!("{err}"),
691 None => format!("<unknown error in FormatMessageW: {message_id}>"),
692 };
693 let (complete, length) =
694 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
695 if !complete {
696 throw_unsup_format!("FormatMessageW: buffer not big enough");
699 }
700 this.write_int(length.strict_sub(1), dest)?;
702 }
703
704 "GetProcessHeap" if this.frame_in_std() => {
707 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
708 this.write_int(1, dest)?;
711 }
712 "GetModuleHandleA" if this.frame_in_std() => {
713 #[allow(non_snake_case)]
714 let [_lpModuleName] = this.check_shim(abi, sys_conv, link_name, args)?;
715 this.write_int(1, dest)?;
717 }
718 "SetConsoleTextAttribute" if this.frame_in_std() => {
719 #[allow(non_snake_case)]
720 let [_hConsoleOutput, _wAttribute] =
721 this.check_shim(abi, sys_conv, link_name, args)?;
722 this.write_null(dest)?;
724 }
725 "GetConsoleMode" if this.frame_in_std() => {
726 let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?;
727 this.read_target_isize(console)?;
728 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
729 this.write_null(dest)?;
731 }
732 "GetFileType" if this.frame_in_std() => {
733 #[allow(non_snake_case)]
734 let [_hFile] = this.check_shim(abi, sys_conv, link_name, args)?;
735 this.write_null(dest)?;
737 }
738 "AddVectoredExceptionHandler" if this.frame_in_std() => {
739 #[allow(non_snake_case)]
740 let [_First, _Handler] = this.check_shim(abi, sys_conv, link_name, args)?;
741 this.write_int(1, dest)?;
743 }
744 "SetThreadStackGuarantee" if this.frame_in_std() => {
745 #[allow(non_snake_case)]
746 let [_StackSizeInBytes] = this.check_shim(abi, sys_conv, link_name, args)?;
747 this.write_int(1, dest)?;
749 }
750 "SwitchToThread" if this.frame_in_std() => {
752 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
753
754 this.yield_active_thread();
755
756 this.write_null(dest)?;
758 }
759
760 "_Unwind_RaiseException" => {
761 if this.tcx.sess.target.env != "gnu" {
766 throw_unsup_format!(
767 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
768 );
769 }
770 let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
772 this.handle_miri_start_unwind(payload)?;
773 return interp_ok(EmulateItemResult::NeedsUnwind);
774 }
775
776 _ => return interp_ok(EmulateItemResult::NotSupported),
777 }
778
779 interp_ok(EmulateItemResult::NeedsReturn)
780 }
781}