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::*;
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" { Conv::X86Stdcall } else { Conv::C };
144
145 match link_name.as_str() {
154 "GetEnvironmentVariableW" => {
156 let [name, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
157 let result = this.GetEnvironmentVariableW(name, buf, size)?;
158 this.write_scalar(result, dest)?;
159 }
160 "SetEnvironmentVariableW" => {
161 let [name, value] = this.check_shim(abi, sys_conv, link_name, args)?;
162 let result = this.SetEnvironmentVariableW(name, value)?;
163 this.write_scalar(result, dest)?;
164 }
165 "GetEnvironmentStringsW" => {
166 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
167 let result = this.GetEnvironmentStringsW()?;
168 this.write_pointer(result, dest)?;
169 }
170 "FreeEnvironmentStringsW" => {
171 let [env_block] = this.check_shim(abi, sys_conv, link_name, args)?;
172 let result = this.FreeEnvironmentStringsW(env_block)?;
173 this.write_scalar(result, dest)?;
174 }
175 "GetCurrentDirectoryW" => {
176 let [size, buf] = this.check_shim(abi, sys_conv, link_name, args)?;
177 let result = this.GetCurrentDirectoryW(size, buf)?;
178 this.write_scalar(result, dest)?;
179 }
180 "SetCurrentDirectoryW" => {
181 let [path] = this.check_shim(abi, sys_conv, link_name, args)?;
182 let result = this.SetCurrentDirectoryW(path)?;
183 this.write_scalar(result, dest)?;
184 }
185 "GetUserProfileDirectoryW" => {
186 let [token, buf, size] = this.check_shim(abi, sys_conv, link_name, args)?;
187 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
188 this.write_scalar(result, dest)?;
189 }
190 "GetCurrentProcessId" => {
191 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
192 let result = this.GetCurrentProcessId()?;
193 this.write_scalar(result, dest)?;
194 }
195
196 "NtWriteFile" => {
198 let [
199 handle,
200 event,
201 apc_routine,
202 apc_context,
203 io_status_block,
204 buf,
205 n,
206 byte_offset,
207 key,
208 ] = this.check_shim(abi, sys_conv, link_name, args)?;
209 this.NtWriteFile(
210 handle,
211 event,
212 apc_routine,
213 apc_context,
214 io_status_block,
215 buf,
216 n,
217 byte_offset,
218 key,
219 dest,
220 )?;
221 }
222 "NtReadFile" => {
223 let [
224 handle,
225 event,
226 apc_routine,
227 apc_context,
228 io_status_block,
229 buf,
230 n,
231 byte_offset,
232 key,
233 ] = this.check_shim(abi, sys_conv, link_name, args)?;
234 this.NtReadFile(
235 handle,
236 event,
237 apc_routine,
238 apc_context,
239 io_status_block,
240 buf,
241 n,
242 byte_offset,
243 key,
244 dest,
245 )?;
246 }
247 "GetFullPathNameW" => {
248 let [filename, size, buffer, filepart] =
249 this.check_shim(abi, sys_conv, link_name, args)?;
250 this.check_no_isolation("`GetFullPathNameW`")?;
251
252 let filename = this.read_pointer(filename)?;
253 let size = this.read_scalar(size)?.to_u32()?;
254 let buffer = this.read_pointer(buffer)?;
255 let filepart = this.read_pointer(filepart)?;
256
257 if !this.ptr_is_null(filepart)? {
258 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
259 }
260
261 let filename = this.read_path_from_wide_str(filename)?;
262 let result = match win_get_full_path_name(&filename)? {
263 Err(err) => {
264 this.set_last_error(err)?;
265 Scalar::from_u32(0) }
267 Ok(abs_filename) => {
268 Scalar::from_u32(helpers::windows_check_buffer_size(
269 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
270 ))
271 }
274 };
275 this.write_scalar(result, dest)?;
276 }
277 "CreateFileW" => {
278 let [
279 file_name,
280 desired_access,
281 share_mode,
282 security_attributes,
283 creation_disposition,
284 flags_and_attributes,
285 template_file,
286 ] = this.check_shim(abi, sys_conv, link_name, args)?;
287 let handle = this.CreateFileW(
288 file_name,
289 desired_access,
290 share_mode,
291 security_attributes,
292 creation_disposition,
293 flags_and_attributes,
294 template_file,
295 )?;
296 this.write_scalar(handle.to_scalar(this), dest)?;
297 }
298 "GetFileInformationByHandle" => {
299 let [handle, info] = this.check_shim(abi, sys_conv, link_name, args)?;
300 let res = this.GetFileInformationByHandle(handle, info)?;
301 this.write_scalar(res, dest)?;
302 }
303 "DeleteFileW" => {
304 let [file_name] = this.check_shim(abi, sys_conv, link_name, args)?;
305 let res = this.DeleteFileW(file_name)?;
306 this.write_scalar(res, dest)?;
307 }
308 "SetFilePointerEx" => {
309 let [file, distance_to_move, new_file_pointer, move_method] =
310 this.check_shim(abi, sys_conv, link_name, args)?;
311 let res =
312 this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
313 this.write_scalar(res, dest)?;
314 }
315
316 "HeapAlloc" => {
318 let [handle, flags, size] = this.check_shim(abi, sys_conv, link_name, args)?;
319 this.read_target_isize(handle)?;
320 let flags = this.read_scalar(flags)?.to_u32()?;
321 let size = this.read_target_usize(size)?;
322 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
323 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
324 AllocInit::Zero
325 } else {
326 AllocInit::Uninit
327 };
328 let align = this.tcx.pointer_size().bytes().strict_mul(2);
331 let ptr = this.allocate_ptr(
332 Size::from_bytes(size),
333 Align::from_bytes(align).unwrap(),
334 MiriMemoryKind::WinHeap.into(),
335 init,
336 )?;
337 this.write_pointer(ptr, dest)?;
338 }
339 "HeapFree" => {
340 let [handle, flags, ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
341 this.read_target_isize(handle)?;
342 this.read_scalar(flags)?.to_u32()?;
343 let ptr = this.read_pointer(ptr)?;
344 if !this.ptr_is_null(ptr)? {
347 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
348 }
349 this.write_scalar(Scalar::from_i32(1), dest)?;
350 }
351 "HeapReAlloc" => {
352 let [handle, flags, old_ptr, size] =
353 this.check_shim(abi, sys_conv, link_name, args)?;
354 this.read_target_isize(handle)?;
355 this.read_scalar(flags)?.to_u32()?;
356 let old_ptr = this.read_pointer(old_ptr)?;
357 let size = this.read_target_usize(size)?;
358 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
363 old_ptr,
364 None,
365 Size::from_bytes(size),
366 Align::from_bytes(align).unwrap(),
367 MiriMemoryKind::WinHeap.into(),
368 AllocInit::Uninit,
369 )?;
370 this.write_pointer(new_ptr, dest)?;
371 }
372 "LocalFree" => {
373 let [ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
374 let ptr = this.read_pointer(ptr)?;
375 if !this.ptr_is_null(ptr)? {
378 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
379 }
380 this.write_null(dest)?;
381 }
382
383 "SetLastError" => {
385 let [error] = this.check_shim(abi, sys_conv, link_name, args)?;
386 let error = this.read_scalar(error)?;
387 this.set_last_error(error)?;
388 }
389 "GetLastError" => {
390 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
391 let last_error = this.get_last_error()?;
392 this.write_scalar(last_error, dest)?;
393 }
394 "RtlNtStatusToDosError" => {
395 let [status] = this.check_shim(abi, sys_conv, link_name, args)?;
396 let status = this.read_scalar(status)?.to_u32()?;
397 let err = match status {
398 0xC00000A2 => 19,
400 0xC0000098 => 1006,
402 0xC000007F => 112,
404 0xC0000185 => 1117,
406 0xC0000022 => 5,
408 _ => 317,
410 };
411 this.write_scalar(Scalar::from_i32(err), dest)?;
412 }
413
414 "GetSystemInfo" => {
416 let [system_info] = this.check_shim(abi, sys_conv, link_name, args)?;
418 let system_info =
419 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
420 this.write_bytes_ptr(
422 system_info.ptr(),
423 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
424 )?;
425 this.write_int_fields_named(
427 &[
428 ("dwPageSize", this.machine.page_size.into()),
429 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
430 ],
431 &system_info,
432 )?;
433 }
434
435 "TlsAlloc" => {
437 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
441 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
442 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
443 }
444 "TlsGetValue" => {
445 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
446 let key = u128::from(this.read_scalar(key)?.to_u32()?);
447 let active_thread = this.active_thread();
448 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
449 this.write_scalar(ptr, dest)?;
450 }
451 "TlsSetValue" => {
452 let [key, new_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
453 let key = u128::from(this.read_scalar(key)?.to_u32()?);
454 let active_thread = this.active_thread();
455 let new_data = this.read_scalar(new_ptr)?;
456 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
457
458 this.write_int(1, dest)?;
460 }
461 "TlsFree" => {
462 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
463 let key = u128::from(this.read_scalar(key)?.to_u32()?);
464 this.machine.tls.delete_tls_key(key)?;
465
466 this.write_int(1, dest)?;
468 }
469
470 "GetCommandLineW" => {
472 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
473 this.write_pointer(
474 this.machine.cmd_line.expect("machine must be initialized"),
475 dest,
476 )?;
477 }
478
479 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
481 #[allow(non_snake_case)]
482 let [LPFILETIME] = this.check_shim(abi, sys_conv, link_name, args)?;
483 this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
484 }
485 "QueryPerformanceCounter" => {
486 #[allow(non_snake_case)]
487 let [lpPerformanceCount] = this.check_shim(abi, sys_conv, link_name, args)?;
488 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
489 this.write_scalar(result, dest)?;
490 }
491 "QueryPerformanceFrequency" => {
492 #[allow(non_snake_case)]
493 let [lpFrequency] = this.check_shim(abi, sys_conv, link_name, args)?;
494 let result = this.QueryPerformanceFrequency(lpFrequency)?;
495 this.write_scalar(result, dest)?;
496 }
497 "Sleep" => {
498 let [timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
499
500 this.Sleep(timeout)?;
501 }
502 "CreateWaitableTimerExW" => {
503 let [attributes, name, flags, access] =
504 this.check_shim(abi, sys_conv, link_name, args)?;
505 this.read_pointer(attributes)?;
506 this.read_pointer(name)?;
507 this.read_scalar(flags)?.to_u32()?;
508 this.read_scalar(access)?.to_u32()?;
509 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
511 this.set_last_error(not_supported)?;
512 this.write_null(dest)?;
513 }
514
515 "InitOnceBeginInitialize" => {
517 let [ptr, flags, pending, context] =
518 this.check_shim(abi, sys_conv, link_name, args)?;
519 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
520 }
521 "InitOnceComplete" => {
522 let [ptr, flags, context] = this.check_shim(abi, sys_conv, link_name, args)?;
523 let result = this.InitOnceComplete(ptr, flags, context)?;
524 this.write_scalar(result, dest)?;
525 }
526 "WaitOnAddress" => {
527 let [ptr_op, compare_op, size_op, timeout_op] =
528 this.check_shim(abi, sys_conv, link_name, args)?;
529
530 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
531 }
532 "WakeByAddressSingle" => {
533 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
534
535 this.WakeByAddressSingle(ptr_op)?;
536 }
537 "WakeByAddressAll" => {
538 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
539
540 this.WakeByAddressAll(ptr_op)?;
541 }
542
543 "GetProcAddress" => {
545 #[allow(non_snake_case)]
546 let [hModule, lpProcName] = this.check_shim(abi, sys_conv, link_name, args)?;
547 this.read_target_isize(hModule)?;
548 let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
549 if let Ok(name) = str::from_utf8(name)
550 && is_dyn_sym(name)
551 {
552 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
553 this.write_pointer(ptr, dest)?;
554 } else {
555 this.write_null(dest)?;
556 }
557 }
558
559 "CreateThread" => {
561 let [security, stacksize, start, arg, flags, thread] =
562 this.check_shim(abi, sys_conv, link_name, args)?;
563
564 let thread_id =
565 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
566
567 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
568 }
569 "WaitForSingleObject" => {
570 let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
571
572 let ret = this.WaitForSingleObject(handle, timeout)?;
573 this.write_scalar(ret, dest)?;
574 }
575 "GetCurrentProcess" => {
576 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
577
578 this.write_scalar(
579 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
580 dest,
581 )?;
582 }
583 "GetCurrentThread" => {
584 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
585
586 this.write_scalar(
587 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
588 dest,
589 )?;
590 }
591 "SetThreadDescription" => {
592 let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?;
593
594 let handle = this.read_handle(handle, "SetThreadDescription")?;
595 let name = this.read_wide_str(this.read_pointer(name)?)?;
596
597 let thread = match handle {
598 Handle::Thread(thread) => thread,
599 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
600 _ => this.invalid_handle("SetThreadDescription")?,
601 };
602 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
604 this.write_scalar(Scalar::from_u32(0), dest)?;
605 }
606 "GetThreadDescription" => {
607 let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
608
609 let handle = this.read_handle(handle, "GetThreadDescription")?;
610 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
613 Handle::Thread(thread) => thread,
614 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
615 _ => this.invalid_handle("GetThreadDescription")?,
616 };
617 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
619 let name = this.alloc_os_str_as_wide_str(
620 bytes_to_os_str(&name)?,
621 MiriMemoryKind::WinLocal.into(),
622 )?;
623 let name = Scalar::from_maybe_pointer(name, this);
624 let res = Scalar::from_u32(0);
625
626 this.write_scalar(name, &name_ptr)?;
627 this.write_scalar(res, dest)?;
628 }
629
630 "ExitProcess" => {
632 let [code] = this.check_shim(abi, sys_conv, link_name, args)?;
633 let code = this.read_scalar(code)?.to_i32()?;
635 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
636 }
637 "SystemFunction036" => {
638 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
641 let ptr = this.read_pointer(ptr)?;
642 let len = this.read_scalar(len)?.to_u32()?;
643 this.gen_random(ptr, len.into())?;
644 this.write_scalar(Scalar::from_bool(true), dest)?;
645 }
646 "ProcessPrng" => {
647 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
649 let ptr = this.read_pointer(ptr)?;
650 let len = this.read_target_usize(len)?;
651 this.gen_random(ptr, len)?;
652 this.write_int(1, dest)?;
653 }
654 "BCryptGenRandom" => {
655 let [algorithm, ptr, len, flags] =
657 this.check_shim(abi, sys_conv, link_name, args)?;
658 let algorithm = this.read_scalar(algorithm)?;
659 let algorithm = algorithm.to_target_usize(this)?;
660 let ptr = this.read_pointer(ptr)?;
661 let len = this.read_scalar(len)?.to_u32()?;
662 let flags = this.read_scalar(flags)?.to_u32()?;
663 match flags {
664 0 => {
665 if algorithm != 0x81 {
666 throw_unsup_format!(
668 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
669 );
670 }
671 }
672 2 => {
673 if algorithm != 0 {
675 throw_unsup_format!(
676 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
677 );
678 }
679 }
680 _ => {
681 throw_unsup_format!(
682 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
683 );
684 }
685 }
686 this.gen_random(ptr, len.into())?;
687 this.write_null(dest)?; }
689 "GetConsoleScreenBufferInfo" => {
690 let [console, buffer_info] = this.check_shim(abi, sys_conv, link_name, args)?;
692 this.read_target_isize(console)?;
693 this.deref_pointer(buffer_info)?;
695 this.write_null(dest)?;
698 }
699 "GetStdHandle" => {
700 let [which] = this.check_shim(abi, sys_conv, link_name, args)?;
701 let res = this.GetStdHandle(which)?;
702 this.write_scalar(res, dest)?;
703 }
704 "DuplicateHandle" => {
705 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
706 this.check_shim(abi, sys_conv, link_name, args)?;
707 let res = this.DuplicateHandle(
708 src_proc,
709 src_handle,
710 target_proc,
711 target_handle,
712 access,
713 inherit,
714 options,
715 )?;
716 this.write_scalar(res, dest)?;
717 }
718 "CloseHandle" => {
719 let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
720
721 let ret = this.CloseHandle(handle)?;
722
723 this.write_scalar(ret, dest)?;
724 }
725 "GetModuleFileNameW" => {
726 let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?;
727 this.check_no_isolation("`GetModuleFileNameW`")?;
728
729 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
730 let filename = this.read_pointer(filename)?;
731 let size = this.read_scalar(size)?.to_u32()?;
732
733 if handle != Handle::Null {
734 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
735 }
736
737 let path = std::env::current_exe().unwrap();
740 let (all_written, size_needed) =
741 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
742
743 if all_written {
744 this.write_int(size_needed.strict_sub(1), dest)?;
748 } else {
749 this.write_int(size, dest)?;
754 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
755 this.set_last_error(insufficient_buffer)?;
756 }
757 }
758 "FormatMessageW" => {
759 let [flags, module, message_id, language_id, buffer, size, arguments] =
760 this.check_shim(abi, sys_conv, link_name, args)?;
761
762 let flags = this.read_scalar(flags)?.to_u32()?;
763 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
765 let _language_id = this.read_scalar(language_id)?.to_u32()?;
766 let buffer = this.read_pointer(buffer)?;
767 let size = this.read_scalar(size)?.to_u32()?;
768 let _arguments = this.read_pointer(arguments)?;
769
770 if flags != 4096u32 | 512u32 {
773 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
774 }
775
776 let error = this.try_errnum_to_io_error(message_id)?;
777 let formatted = match error {
778 Some(err) => format!("{err}"),
779 None => format!("<unknown error in FormatMessageW: {message_id}>"),
780 };
781 let (complete, length) =
782 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
783 if !complete {
784 throw_unsup_format!("FormatMessageW: buffer not big enough");
787 }
788 this.write_int(length.strict_sub(1), dest)?;
790 }
791
792 "GetProcessHeap" if this.frame_in_std() => {
795 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
796 this.write_int(1, dest)?;
799 }
800 "GetModuleHandleA" if this.frame_in_std() => {
801 #[allow(non_snake_case)]
802 let [_lpModuleName] = this.check_shim(abi, sys_conv, link_name, args)?;
803 this.write_int(1, dest)?;
805 }
806 "SetConsoleTextAttribute" if this.frame_in_std() => {
807 #[allow(non_snake_case)]
808 let [_hConsoleOutput, _wAttribute] =
809 this.check_shim(abi, sys_conv, link_name, args)?;
810 this.write_null(dest)?;
812 }
813 "GetConsoleMode" if this.frame_in_std() => {
814 let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?;
815 this.read_target_isize(console)?;
816 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
817 this.write_null(dest)?;
819 }
820 "GetFileType" if this.frame_in_std() => {
821 #[allow(non_snake_case)]
822 let [_hFile] = this.check_shim(abi, sys_conv, link_name, args)?;
823 this.write_null(dest)?;
825 }
826 "AddVectoredExceptionHandler" if this.frame_in_std() => {
827 #[allow(non_snake_case)]
828 let [_First, _Handler] = this.check_shim(abi, sys_conv, link_name, args)?;
829 this.write_int(1, dest)?;
831 }
832 "SetThreadStackGuarantee" if this.frame_in_std() => {
833 #[allow(non_snake_case)]
834 let [_StackSizeInBytes] = this.check_shim(abi, sys_conv, link_name, args)?;
835 this.write_int(1, dest)?;
837 }
838 "SwitchToThread" if this.frame_in_std() => {
840 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
841
842 this.yield_active_thread();
843
844 this.write_null(dest)?;
846 }
847
848 "_Unwind_RaiseException" => {
849 if this.tcx.sess.target.env != "gnu" {
854 throw_unsup_format!(
855 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
856 );
857 }
858 let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
860 this.handle_miri_start_unwind(payload)?;
861 return interp_ok(EmulateItemResult::NeedsUnwind);
862 }
863
864 _ => return interp_ok(EmulateItemResult::NotSupported),
865 }
866
867 interp_ok(EmulateItemResult::NeedsReturn)
868 }
869}