1use std::ffi::OsStr;
2use std::path::{self, Path, PathBuf};
3use std::{io, iter, str};
4
5use rustc_abi::{Align, CanonAbi, Size, X86Call};
6use rustc_middle::ty::Ty;
7use rustc_span::Symbol;
8use rustc_target::callconv::FnAbi;
9
10use self::shims::windows::handle::{Handle, PseudoHandle};
11use crate::shims::os_str::bytes_to_os_str;
12use crate::shims::windows::*;
13use crate::*;
14
15pub fn is_dyn_sym(name: &str) -> bool {
16 matches!(
18 name,
19 "SetThreadDescription" | "GetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle"
20 )
21}
22
23#[cfg(windows)]
24fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
25 interp_ok(path::absolute(path))
27}
28
29#[cfg(unix)]
30#[expect(clippy::get_first, clippy::arithmetic_side_effects)]
31fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
32 use std::sync::LazyLock;
33
34 use rustc_data_structures::fx::FxHashSet;
35
36 let bytes = path.as_os_str().as_encoded_bytes();
44 if bytes.get(0).copied() == Some(b'/')
47 && bytes.get(1).copied() == Some(b'/')
48 && matches!(bytes.get(2), Some(b'.' | b'?'))
49 && bytes.get(3).copied() == Some(b'/')
50 {
51 return interp_ok(Ok(path.into()));
52 };
53 let is_unc = bytes.starts_with(b"//");
54 static MAGIC_FILENAMES: LazyLock<FxHashSet<&'static str>> = LazyLock::new(|| {
56 FxHashSet::from_iter([
57 "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
58 "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
59 ])
60 });
61 if str::from_utf8(bytes).is_ok_and(|s| MAGIC_FILENAMES.contains(&*s.to_ascii_uppercase())) {
62 let mut result: Vec<u8> = b"//./".into();
63 result.extend(bytes);
64 return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
65 }
66 let mut result: Vec<&[u8]> = vec![]; let mut bytes = bytes; let mut stop = false;
71 while !stop {
72 let mut component = match bytes.iter().position(|&b| b == b'/') {
74 Some(pos) => {
75 let (component, tail) = bytes.split_at(pos);
76 bytes = &tail[1..]; component
78 }
79 None => {
80 stop = true;
82 let component = bytes;
83 bytes = &[];
84 component
85 }
86 };
87 if !is_unc && component.eq_ignore_ascii_case(b"NUL") {
91 let mut result: Vec<u8> = b"//./".into();
92 result.extend(component);
93 return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
94 }
95 if component == b".." {
97 let is_root = {
99 result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':'])
101 } || {
102 result.len() == 4 && matches!(result[0], []) && matches!(result[1], [])
104 };
105 if !is_root {
106 result.pop();
107 }
108 continue;
109 }
110 let len = component.len();
113 if !is_unc && len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' {
114 component = &component[..len - 1];
115 }
116 result.push(component);
118 }
119 if result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':']) {
121 result.push(&[]);
122 }
123 let result = result.join(&b'/');
125 interp_ok(path::absolute(bytes_to_os_str(&result)?))
126}
127
128impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
129pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
130 fn emulate_foreign_item_inner(
131 &mut self,
132 link_name: Symbol,
133 abi: &FnAbi<'tcx, Ty<'tcx>>,
134 args: &[OpTy<'tcx>],
135 dest: &MPlaceTy<'tcx>,
136 ) -> InterpResult<'tcx, EmulateItemResult> {
137 let this = self.eval_context_mut();
138
139 let sys_conv = if this.tcx.sess.target.arch == "x86" {
144 CanonAbi::X86(X86Call::Stdcall)
145 } else {
146 CanonAbi::C
147 };
148
149 match link_name.as_str() {
158 "GetEnvironmentVariableW" => {
160 let [name, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
161 let result = this.GetEnvironmentVariableW(name, buf, size)?;
162 this.write_scalar(result, dest)?;
163 }
164 "SetEnvironmentVariableW" => {
165 let [name, value] = this.check_shim(abi, sys_conv, link_name, args)?;
166 let result = this.SetEnvironmentVariableW(name, value)?;
167 this.write_scalar(result, dest)?;
168 }
169 "GetEnvironmentStringsW" => {
170 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
171 let result = this.GetEnvironmentStringsW()?;
172 this.write_pointer(result, dest)?;
173 }
174 "FreeEnvironmentStringsW" => {
175 let [env_block] = this.check_shim(abi, sys_conv, link_name, args)?;
176 let result = this.FreeEnvironmentStringsW(env_block)?;
177 this.write_scalar(result, dest)?;
178 }
179 "GetCurrentDirectoryW" => {
180 let [size, buf] = this.check_shim(abi, sys_conv, link_name, args)?;
181 let result = this.GetCurrentDirectoryW(size, buf)?;
182 this.write_scalar(result, dest)?;
183 }
184 "SetCurrentDirectoryW" => {
185 let [path] = this.check_shim(abi, sys_conv, link_name, args)?;
186 let result = this.SetCurrentDirectoryW(path)?;
187 this.write_scalar(result, dest)?;
188 }
189 "GetUserProfileDirectoryW" => {
190 let [token, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
191 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
192 this.write_scalar(result, dest)?;
193 }
194 "GetCurrentProcessId" => {
195 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
196 let result = this.GetCurrentProcessId()?;
197 this.write_scalar(result, dest)?;
198 }
199
200 "NtWriteFile" => {
202 let [
203 handle,
204 event,
205 apc_routine,
206 apc_context,
207 io_status_block,
208 buf,
209 n,
210 byte_offset,
211 key,
212 ] = this.check_shim(abi, sys_conv, link_name, args)?;
213 this.NtWriteFile(
214 handle,
215 event,
216 apc_routine,
217 apc_context,
218 io_status_block,
219 buf,
220 n,
221 byte_offset,
222 key,
223 dest,
224 )?;
225 }
226 "NtReadFile" => {
227 let [
228 handle,
229 event,
230 apc_routine,
231 apc_context,
232 io_status_block,
233 buf,
234 n,
235 byte_offset,
236 key,
237 ] = this.check_shim(abi, sys_conv, link_name, args)?;
238 this.NtReadFile(
239 handle,
240 event,
241 apc_routine,
242 apc_context,
243 io_status_block,
244 buf,
245 n,
246 byte_offset,
247 key,
248 dest,
249 )?;
250 }
251 "GetFullPathNameW" => {
252 let [filename, size, buffer, filepart] =
253 this.check_shim(abi, sys_conv, link_name, args)?;
254 this.check_no_isolation("`GetFullPathNameW`")?;
255
256 let filename = this.read_pointer(filename)?;
257 let size = this.read_scalar(size)?.to_u32()?;
258 let buffer = this.read_pointer(buffer)?;
259 let filepart = this.read_pointer(filepart)?;
260
261 if !this.ptr_is_null(filepart)? {
262 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
263 }
264
265 let filename = this.read_path_from_wide_str(filename)?;
266 let result = match win_get_full_path_name(&filename)? {
267 Err(err) => {
268 this.set_last_error(err)?;
269 Scalar::from_u32(0) }
271 Ok(abs_filename) => {
272 Scalar::from_u32(helpers::windows_check_buffer_size(
273 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
274 ))
275 }
278 };
279 this.write_scalar(result, dest)?;
280 }
281 "CreateFileW" => {
282 let [
283 file_name,
284 desired_access,
285 share_mode,
286 security_attributes,
287 creation_disposition,
288 flags_and_attributes,
289 template_file,
290 ] = this.check_shim(abi, sys_conv, link_name, args)?;
291 let handle = this.CreateFileW(
292 file_name,
293 desired_access,
294 share_mode,
295 security_attributes,
296 creation_disposition,
297 flags_and_attributes,
298 template_file,
299 )?;
300 this.write_scalar(handle.to_scalar(this), dest)?;
301 }
302 "GetFileInformationByHandle" => {
303 let [handle, info] = this.check_shim(abi, sys_conv, link_name, args)?;
304 let res = this.GetFileInformationByHandle(handle, info)?;
305 this.write_scalar(res, dest)?;
306 }
307 "DeleteFileW" => {
308 let [file_name] = this.check_shim(abi, sys_conv, link_name, args)?;
309 let res = this.DeleteFileW(file_name)?;
310 this.write_scalar(res, dest)?;
311 }
312 "SetFilePointerEx" => {
313 let [file, distance_to_move, new_file_pointer, move_method] =
314 this.check_shim(abi, sys_conv, link_name, args)?;
315 let res =
316 this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
317 this.write_scalar(res, dest)?;
318 }
319
320 "HeapAlloc" => {
322 let [handle, flags, size] = this.check_shim(abi, sys_conv, link_name, args)?;
323 this.read_target_isize(handle)?;
324 let flags = this.read_scalar(flags)?.to_u32()?;
325 let size = this.read_target_usize(size)?;
326 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
327 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
328 AllocInit::Zero
329 } else {
330 AllocInit::Uninit
331 };
332 let align = this.tcx.pointer_size().bytes().strict_mul(2);
335 let ptr = this.allocate_ptr(
336 Size::from_bytes(size),
337 Align::from_bytes(align).unwrap(),
338 MiriMemoryKind::WinHeap.into(),
339 init,
340 )?;
341 this.write_pointer(ptr, dest)?;
342 }
343 "HeapFree" => {
344 let [handle, flags, ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
345 this.read_target_isize(handle)?;
346 this.read_scalar(flags)?.to_u32()?;
347 let ptr = this.read_pointer(ptr)?;
348 if !this.ptr_is_null(ptr)? {
351 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
352 }
353 this.write_scalar(Scalar::from_i32(1), dest)?;
354 }
355 "HeapReAlloc" => {
356 let [handle, flags, old_ptr, size] =
357 this.check_shim(abi, sys_conv, link_name, args)?;
358 this.read_target_isize(handle)?;
359 this.read_scalar(flags)?.to_u32()?;
360 let old_ptr = this.read_pointer(old_ptr)?;
361 let size = this.read_target_usize(size)?;
362 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
367 old_ptr,
368 None,
369 Size::from_bytes(size),
370 Align::from_bytes(align).unwrap(),
371 MiriMemoryKind::WinHeap.into(),
372 AllocInit::Uninit,
373 )?;
374 this.write_pointer(new_ptr, dest)?;
375 }
376 "LocalFree" => {
377 let [ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
378 let ptr = this.read_pointer(ptr)?;
379 if !this.ptr_is_null(ptr)? {
382 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
383 }
384 this.write_null(dest)?;
385 }
386
387 "SetLastError" => {
389 let [error] = this.check_shim(abi, sys_conv, link_name, args)?;
390 let error = this.read_scalar(error)?;
391 this.set_last_error(error)?;
392 }
393 "GetLastError" => {
394 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
395 let last_error = this.get_last_error()?;
396 this.write_scalar(last_error, dest)?;
397 }
398 "RtlNtStatusToDosError" => {
399 let [status] = this.check_shim(abi, sys_conv, link_name, args)?;
400 let status = this.read_scalar(status)?.to_u32()?;
401 let err = match status {
402 0xC00000A2 => 19,
404 0xC0000098 => 1006,
406 0xC000007F => 112,
408 0xC0000185 => 1117,
410 0xC0000022 => 5,
412 _ => 317,
414 };
415 this.write_scalar(Scalar::from_i32(err), dest)?;
416 }
417
418 "GetSystemInfo" => {
420 let [system_info] = this.check_shim(abi, sys_conv, link_name, args)?;
422 let system_info =
423 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
424 this.write_bytes_ptr(
426 system_info.ptr(),
427 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
428 )?;
429 this.write_int_fields_named(
431 &[
432 ("dwPageSize", this.machine.page_size.into()),
433 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
434 ],
435 &system_info,
436 )?;
437 }
438
439 "TlsAlloc" => {
441 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
445 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
446 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
447 }
448 "TlsGetValue" => {
449 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
450 let key = u128::from(this.read_scalar(key)?.to_u32()?);
451 let active_thread = this.active_thread();
452 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
453 this.write_scalar(ptr, dest)?;
454 }
455 "TlsSetValue" => {
456 let [key, new_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
457 let key = u128::from(this.read_scalar(key)?.to_u32()?);
458 let active_thread = this.active_thread();
459 let new_data = this.read_scalar(new_ptr)?;
460 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
461
462 this.write_int(1, dest)?;
464 }
465 "TlsFree" => {
466 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
467 let key = u128::from(this.read_scalar(key)?.to_u32()?);
468 this.machine.tls.delete_tls_key(key)?;
469
470 this.write_int(1, dest)?;
472 }
473
474 "GetCommandLineW" => {
476 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
477 this.write_pointer(
478 this.machine.cmd_line.expect("machine must be initialized"),
479 dest,
480 )?;
481 }
482
483 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
485 #[allow(non_snake_case)]
486 let [LPFILETIME] = this.check_shim(abi, sys_conv, link_name, args)?;
487 this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
488 }
489 "QueryPerformanceCounter" => {
490 #[allow(non_snake_case)]
491 let [lpPerformanceCount] = this.check_shim(abi, sys_conv, link_name, args)?;
492 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
493 this.write_scalar(result, dest)?;
494 }
495 "QueryPerformanceFrequency" => {
496 #[allow(non_snake_case)]
497 let [lpFrequency] = this.check_shim(abi, sys_conv, link_name, args)?;
498 let result = this.QueryPerformanceFrequency(lpFrequency)?;
499 this.write_scalar(result, dest)?;
500 }
501 "Sleep" => {
502 let [timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
503
504 this.Sleep(timeout)?;
505 }
506 "CreateWaitableTimerExW" => {
507 let [attributes, name, flags, access] =
508 this.check_shim(abi, sys_conv, link_name, args)?;
509 this.read_pointer(attributes)?;
510 this.read_pointer(name)?;
511 this.read_scalar(flags)?.to_u32()?;
512 this.read_scalar(access)?.to_u32()?;
513 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
515 this.set_last_error(not_supported)?;
516 this.write_null(dest)?;
517 }
518
519 "InitOnceBeginInitialize" => {
521 let [ptr, flags, pending, context] =
522 this.check_shim(abi, sys_conv, link_name, args)?;
523 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
524 }
525 "InitOnceComplete" => {
526 let [ptr, flags, context] = this.check_shim(abi, sys_conv, link_name, args)?;
527 let result = this.InitOnceComplete(ptr, flags, context)?;
528 this.write_scalar(result, dest)?;
529 }
530 "WaitOnAddress" => {
531 let [ptr_op, compare_op, size_op, timeout_op] =
532 this.check_shim(abi, sys_conv, link_name, args)?;
533
534 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
535 }
536 "WakeByAddressSingle" => {
537 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
538
539 this.WakeByAddressSingle(ptr_op)?;
540 }
541 "WakeByAddressAll" => {
542 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
543
544 this.WakeByAddressAll(ptr_op)?;
545 }
546
547 "GetProcAddress" => {
549 #[allow(non_snake_case)]
550 let [hModule, lpProcName] = this.check_shim(abi, sys_conv, link_name, args)?;
551 this.read_target_isize(hModule)?;
552 let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
553 if let Ok(name) = str::from_utf8(name)
554 && is_dyn_sym(name)
555 {
556 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
557 this.write_pointer(ptr, dest)?;
558 } else {
559 this.write_null(dest)?;
560 }
561 }
562
563 "CreateThread" => {
565 let [security, stacksize, start, arg, flags, thread] =
566 this.check_shim(abi, sys_conv, link_name, args)?;
567
568 let thread_id =
569 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
570
571 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
572 }
573 "WaitForSingleObject" => {
574 let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
575
576 this.WaitForSingleObject(handle, timeout, dest)?;
577 }
578 "GetCurrentProcess" => {
579 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
580
581 this.write_scalar(
582 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
583 dest,
584 )?;
585 }
586 "GetCurrentThread" => {
587 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
588
589 this.write_scalar(
590 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
591 dest,
592 )?;
593 }
594 "SetThreadDescription" => {
595 let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?;
596
597 let handle = this.read_handle(handle, "SetThreadDescription")?;
598 let name = this.read_wide_str(this.read_pointer(name)?)?;
599
600 let thread = match handle {
601 Handle::Thread(thread) => thread,
602 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
603 _ => this.invalid_handle("SetThreadDescription")?,
604 };
605 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
607 this.write_scalar(Scalar::from_u32(0), dest)?;
608 }
609 "GetThreadDescription" => {
610 let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
611
612 let handle = this.read_handle(handle, "GetThreadDescription")?;
613 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
616 Handle::Thread(thread) => thread,
617 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
618 _ => this.invalid_handle("GetThreadDescription")?,
619 };
620 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
622 let name = this.alloc_os_str_as_wide_str(
623 bytes_to_os_str(&name)?,
624 MiriMemoryKind::WinLocal.into(),
625 )?;
626 let name = Scalar::from_maybe_pointer(name, this);
627 let res = Scalar::from_u32(0);
628
629 this.write_scalar(name, &name_ptr)?;
630 this.write_scalar(res, dest)?;
631 }
632
633 "ExitProcess" => {
635 let [code] = this.check_shim(abi, sys_conv, link_name, args)?;
636 let code = this.read_scalar(code)?.to_i32()?;
638 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
639 }
640 "SystemFunction036" => {
641 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
644 let ptr = this.read_pointer(ptr)?;
645 let len = this.read_scalar(len)?.to_u32()?;
646 this.gen_random(ptr, len.into())?;
647 this.write_scalar(Scalar::from_bool(true), dest)?;
648 }
649 "ProcessPrng" => {
650 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
652 let ptr = this.read_pointer(ptr)?;
653 let len = this.read_target_usize(len)?;
654 this.gen_random(ptr, len)?;
655 this.write_int(1, dest)?;
656 }
657 "BCryptGenRandom" => {
658 let [algorithm, ptr, len, flags] =
660 this.check_shim(abi, sys_conv, link_name, args)?;
661 let algorithm = this.read_scalar(algorithm)?;
662 let algorithm = algorithm.to_target_usize(this)?;
663 let ptr = this.read_pointer(ptr)?;
664 let len = this.read_scalar(len)?.to_u32()?;
665 let flags = this.read_scalar(flags)?.to_u32()?;
666 match flags {
667 0 => {
668 if algorithm != 0x81 {
669 throw_unsup_format!(
671 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
672 );
673 }
674 }
675 2 => {
676 if algorithm != 0 {
678 throw_unsup_format!(
679 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
680 );
681 }
682 }
683 _ => {
684 throw_unsup_format!(
685 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
686 );
687 }
688 }
689 this.gen_random(ptr, len.into())?;
690 this.write_null(dest)?; }
692 "GetConsoleScreenBufferInfo" => {
693 let [console, buffer_info] = this.check_shim(abi, sys_conv, link_name, args)?;
695 this.read_target_isize(console)?;
696 this.deref_pointer(buffer_info)?;
698 this.write_null(dest)?;
701 }
702 "GetStdHandle" => {
703 let [which] = this.check_shim(abi, sys_conv, link_name, args)?;
704 let res = this.GetStdHandle(which)?;
705 this.write_scalar(res, dest)?;
706 }
707 "DuplicateHandle" => {
708 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
709 this.check_shim(abi, sys_conv, link_name, args)?;
710 let res = this.DuplicateHandle(
711 src_proc,
712 src_handle,
713 target_proc,
714 target_handle,
715 access,
716 inherit,
717 options,
718 )?;
719 this.write_scalar(res, dest)?;
720 }
721 "CloseHandle" => {
722 let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
723
724 let ret = this.CloseHandle(handle)?;
725
726 this.write_scalar(ret, dest)?;
727 }
728 "GetModuleFileNameW" => {
729 let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?;
730 this.check_no_isolation("`GetModuleFileNameW`")?;
731
732 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
733 let filename = this.read_pointer(filename)?;
734 let size = this.read_scalar(size)?.to_u32()?;
735
736 if handle != Handle::Null {
737 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
738 }
739
740 let path = std::env::current_exe().unwrap();
743 let (all_written, size_needed) =
744 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
745
746 if all_written {
747 this.write_int(size_needed.strict_sub(1), dest)?;
751 } else {
752 this.write_int(size, dest)?;
757 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
758 this.set_last_error(insufficient_buffer)?;
759 }
760 }
761 "FormatMessageW" => {
762 let [flags, module, message_id, language_id, buffer, size, arguments] =
763 this.check_shim(abi, sys_conv, link_name, args)?;
764
765 let flags = this.read_scalar(flags)?.to_u32()?;
766 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
768 let _language_id = this.read_scalar(language_id)?.to_u32()?;
769 let buffer = this.read_pointer(buffer)?;
770 let size = this.read_scalar(size)?.to_u32()?;
771 let _arguments = this.read_pointer(arguments)?;
772
773 if flags != 4096u32 | 512u32 {
776 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
777 }
778
779 let error = this.try_errnum_to_io_error(message_id)?;
780 let formatted = match error {
781 Some(err) => format!("{err}"),
782 None => format!("<unknown error in FormatMessageW: {message_id}>"),
783 };
784 let (complete, length) =
785 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
786 if !complete {
787 throw_unsup_format!("FormatMessageW: buffer not big enough");
790 }
791 this.write_int(length.strict_sub(1), dest)?;
793 }
794
795 "GetProcessHeap" if this.frame_in_std() => {
798 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
799 this.write_int(1, dest)?;
802 }
803 "GetModuleHandleA" if this.frame_in_std() => {
804 #[allow(non_snake_case)]
805 let [_lpModuleName] = this.check_shim(abi, sys_conv, link_name, args)?;
806 this.write_int(1, dest)?;
808 }
809 "SetConsoleTextAttribute" if this.frame_in_std() => {
810 #[allow(non_snake_case)]
811 let [_hConsoleOutput, _wAttribute] =
812 this.check_shim(abi, sys_conv, link_name, args)?;
813 this.write_null(dest)?;
815 }
816 "GetConsoleMode" if this.frame_in_std() => {
817 let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?;
818 this.read_target_isize(console)?;
819 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
820 this.write_null(dest)?;
822 }
823 "GetFileType" if this.frame_in_std() => {
824 #[allow(non_snake_case)]
825 let [_hFile] = this.check_shim(abi, sys_conv, link_name, args)?;
826 this.write_null(dest)?;
828 }
829 "AddVectoredExceptionHandler" if this.frame_in_std() => {
830 #[allow(non_snake_case)]
831 let [_First, _Handler] = this.check_shim(abi, sys_conv, link_name, args)?;
832 this.write_int(1, dest)?;
834 }
835 "SetThreadStackGuarantee" if this.frame_in_std() => {
836 #[allow(non_snake_case)]
837 let [_StackSizeInBytes] = this.check_shim(abi, sys_conv, link_name, args)?;
838 this.write_int(1, dest)?;
840 }
841 "SwitchToThread" if this.frame_in_std() => {
843 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
844
845 this.yield_active_thread();
846
847 this.write_null(dest)?;
849 }
850
851 "_Unwind_RaiseException" => {
852 if this.tcx.sess.target.env != "gnu" {
857 throw_unsup_format!(
858 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
859 );
860 }
861 let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
863 this.handle_miri_start_unwind(payload)?;
864 return interp_ok(EmulateItemResult::NeedsUnwind);
865 }
866
867 _ => return interp_ok(EmulateItemResult::NotSupported),
868 }
869
870 interp_ok(EmulateItemResult::NeedsReturn)
871 }
872}