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 if !this.frame_in_std() {
199 throw_unsup_format!(
200 "`NtWriteFile` support is crude and just enough for stdout to work"
201 );
202 }
203
204 let [
205 handle,
206 _event,
207 _apc_routine,
208 _apc_context,
209 io_status_block,
210 buf,
211 n,
212 byte_offset,
213 _key,
214 ] = this.check_shim(abi, sys_conv, link_name, args)?;
215 let handle = this.read_target_isize(handle)?;
216 let buf = this.read_pointer(buf)?;
217 let n = this.read_scalar(n)?.to_u32()?;
218 let byte_offset = this.read_target_usize(byte_offset)?; let io_status_block = this
220 .deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
221
222 if byte_offset != 0 {
223 throw_unsup_format!(
224 "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported"
225 );
226 }
227
228 let written = if handle == -11 || handle == -12 {
229 use io::Write;
231
232 let buf_cont =
233 this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
234 let res = if this.machine.mute_stdout_stderr {
235 Ok(buf_cont.len())
236 } else if handle == -11 {
237 io::stdout().write(buf_cont)
238 } else {
239 io::stderr().write(buf_cont)
240 };
241 res.ok().map(|n| u32::try_from(n).unwrap())
243 } else {
244 throw_unsup_format!(
245 "on Windows, writing to anything except stdout/stderr is not supported"
246 )
247 };
248 if let Some(n) = written {
250 let io_status_information =
251 this.project_field_named(&io_status_block, "Information")?;
252 this.write_scalar(
253 Scalar::from_target_usize(n.into(), this),
254 &io_status_information,
255 )?;
256 }
257 this.write_scalar(
260 Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
261 dest,
262 )?;
263 }
264 "GetFullPathNameW" => {
265 let [filename, size, buffer, filepart] =
266 this.check_shim(abi, sys_conv, link_name, args)?;
267 this.check_no_isolation("`GetFullPathNameW`")?;
268
269 let filename = this.read_pointer(filename)?;
270 let size = this.read_scalar(size)?.to_u32()?;
271 let buffer = this.read_pointer(buffer)?;
272 let filepart = this.read_pointer(filepart)?;
273
274 if !this.ptr_is_null(filepart)? {
275 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
276 }
277
278 let filename = this.read_path_from_wide_str(filename)?;
279 let result = match win_get_full_path_name(&filename)? {
280 Err(err) => {
281 this.set_last_error(err)?;
282 Scalar::from_u32(0) }
284 Ok(abs_filename) => {
285 Scalar::from_u32(helpers::windows_check_buffer_size(
286 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
287 ))
288 }
291 };
292 this.write_scalar(result, dest)?;
293 }
294 "CreateFileW" => {
295 let [
296 file_name,
297 desired_access,
298 share_mode,
299 security_attributes,
300 creation_disposition,
301 flags_and_attributes,
302 template_file,
303 ] = this.check_shim(abi, sys_conv, link_name, args)?;
304 let handle = this.CreateFileW(
305 file_name,
306 desired_access,
307 share_mode,
308 security_attributes,
309 creation_disposition,
310 flags_and_attributes,
311 template_file,
312 )?;
313 this.write_scalar(handle.to_scalar(this), dest)?;
314 }
315 "GetFileInformationByHandle" => {
316 let [handle, info] = this.check_shim(abi, sys_conv, link_name, args)?;
317 let res = this.GetFileInformationByHandle(handle, info)?;
318 this.write_scalar(res, dest)?;
319 }
320 "DeleteFileW" => {
321 let [file_name] = this.check_shim(abi, sys_conv, link_name, args)?;
322 let res = this.DeleteFileW(file_name)?;
323 this.write_scalar(res, dest)?;
324 }
325
326 "HeapAlloc" => {
328 let [handle, flags, size] = this.check_shim(abi, sys_conv, link_name, args)?;
329 this.read_target_isize(handle)?;
330 let flags = this.read_scalar(flags)?.to_u32()?;
331 let size = this.read_target_usize(size)?;
332 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
333 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
334 AllocInit::Zero
335 } else {
336 AllocInit::Uninit
337 };
338 let align = this.tcx.pointer_size().bytes().strict_mul(2);
341 let ptr = this.allocate_ptr(
342 Size::from_bytes(size),
343 Align::from_bytes(align).unwrap(),
344 MiriMemoryKind::WinHeap.into(),
345 init,
346 )?;
347 this.write_pointer(ptr, dest)?;
348 }
349 "HeapFree" => {
350 let [handle, flags, ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
351 this.read_target_isize(handle)?;
352 this.read_scalar(flags)?.to_u32()?;
353 let ptr = this.read_pointer(ptr)?;
354 if !this.ptr_is_null(ptr)? {
357 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
358 }
359 this.write_scalar(Scalar::from_i32(1), dest)?;
360 }
361 "HeapReAlloc" => {
362 let [handle, flags, old_ptr, size] =
363 this.check_shim(abi, sys_conv, link_name, args)?;
364 this.read_target_isize(handle)?;
365 this.read_scalar(flags)?.to_u32()?;
366 let old_ptr = this.read_pointer(old_ptr)?;
367 let size = this.read_target_usize(size)?;
368 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
373 old_ptr,
374 None,
375 Size::from_bytes(size),
376 Align::from_bytes(align).unwrap(),
377 MiriMemoryKind::WinHeap.into(),
378 AllocInit::Uninit,
379 )?;
380 this.write_pointer(new_ptr, dest)?;
381 }
382 "LocalFree" => {
383 let [ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
384 let ptr = this.read_pointer(ptr)?;
385 if !this.ptr_is_null(ptr)? {
388 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
389 }
390 this.write_null(dest)?;
391 }
392
393 "SetLastError" => {
395 let [error] = this.check_shim(abi, sys_conv, link_name, args)?;
396 let error = this.read_scalar(error)?;
397 this.set_last_error(error)?;
398 }
399 "GetLastError" => {
400 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
401 let last_error = this.get_last_error()?;
402 this.write_scalar(last_error, dest)?;
403 }
404 "RtlNtStatusToDosError" => {
405 let [status] = this.check_shim(abi, sys_conv, link_name, args)?;
406 let status = this.read_scalar(status)?.to_u32()?;
407 let err = match status {
408 0xC00000A2 => 19,
410 0xC0000098 => 1006,
412 0xC000007F => 112,
414 0xC0000185 => 1117,
416 0xC0000022 => 5,
418 _ => 317,
420 };
421 this.write_scalar(Scalar::from_i32(err), dest)?;
422 }
423
424 "GetSystemInfo" => {
426 let [system_info] = this.check_shim(abi, sys_conv, link_name, args)?;
428 let system_info =
429 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
430 this.write_bytes_ptr(
432 system_info.ptr(),
433 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
434 )?;
435 this.write_int_fields_named(
437 &[
438 ("dwPageSize", this.machine.page_size.into()),
439 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
440 ],
441 &system_info,
442 )?;
443 }
444
445 "TlsAlloc" => {
447 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
451 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
452 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
453 }
454 "TlsGetValue" => {
455 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
456 let key = u128::from(this.read_scalar(key)?.to_u32()?);
457 let active_thread = this.active_thread();
458 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
459 this.write_scalar(ptr, dest)?;
460 }
461 "TlsSetValue" => {
462 let [key, new_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
463 let key = u128::from(this.read_scalar(key)?.to_u32()?);
464 let active_thread = this.active_thread();
465 let new_data = this.read_scalar(new_ptr)?;
466 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
467
468 this.write_int(1, dest)?;
470 }
471 "TlsFree" => {
472 let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
473 let key = u128::from(this.read_scalar(key)?.to_u32()?);
474 this.machine.tls.delete_tls_key(key)?;
475
476 this.write_int(1, dest)?;
478 }
479
480 "GetCommandLineW" => {
482 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
483 this.write_pointer(
484 this.machine.cmd_line.expect("machine must be initialized"),
485 dest,
486 )?;
487 }
488
489 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
491 #[allow(non_snake_case)]
492 let [LPFILETIME] = this.check_shim(abi, sys_conv, link_name, args)?;
493 this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
494 }
495 "QueryPerformanceCounter" => {
496 #[allow(non_snake_case)]
497 let [lpPerformanceCount] = this.check_shim(abi, sys_conv, link_name, args)?;
498 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
499 this.write_scalar(result, dest)?;
500 }
501 "QueryPerformanceFrequency" => {
502 #[allow(non_snake_case)]
503 let [lpFrequency] = this.check_shim(abi, sys_conv, link_name, args)?;
504 let result = this.QueryPerformanceFrequency(lpFrequency)?;
505 this.write_scalar(result, dest)?;
506 }
507 "Sleep" => {
508 let [timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
509
510 this.Sleep(timeout)?;
511 }
512 "CreateWaitableTimerExW" => {
513 let [attributes, name, flags, access] =
514 this.check_shim(abi, sys_conv, link_name, args)?;
515 this.read_pointer(attributes)?;
516 this.read_pointer(name)?;
517 this.read_scalar(flags)?.to_u32()?;
518 this.read_scalar(access)?.to_u32()?;
519 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
521 this.set_last_error(not_supported)?;
522 this.write_null(dest)?;
523 }
524
525 "InitOnceBeginInitialize" => {
527 let [ptr, flags, pending, context] =
528 this.check_shim(abi, sys_conv, link_name, args)?;
529 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
530 }
531 "InitOnceComplete" => {
532 let [ptr, flags, context] = this.check_shim(abi, sys_conv, link_name, args)?;
533 let result = this.InitOnceComplete(ptr, flags, context)?;
534 this.write_scalar(result, dest)?;
535 }
536 "WaitOnAddress" => {
537 let [ptr_op, compare_op, size_op, timeout_op] =
538 this.check_shim(abi, sys_conv, link_name, args)?;
539
540 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
541 }
542 "WakeByAddressSingle" => {
543 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
544
545 this.WakeByAddressSingle(ptr_op)?;
546 }
547 "WakeByAddressAll" => {
548 let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
549
550 this.WakeByAddressAll(ptr_op)?;
551 }
552
553 "GetProcAddress" => {
555 #[allow(non_snake_case)]
556 let [hModule, lpProcName] = this.check_shim(abi, sys_conv, link_name, args)?;
557 this.read_target_isize(hModule)?;
558 let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
559 if let Ok(name) = str::from_utf8(name)
560 && is_dyn_sym(name)
561 {
562 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
563 this.write_pointer(ptr, dest)?;
564 } else {
565 this.write_null(dest)?;
566 }
567 }
568
569 "CreateThread" => {
571 let [security, stacksize, start, arg, flags, thread] =
572 this.check_shim(abi, sys_conv, link_name, args)?;
573
574 let thread_id =
575 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
576
577 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
578 }
579 "WaitForSingleObject" => {
580 let [handle, timeout] = this.check_shim(abi, sys_conv, link_name, args)?;
581
582 let ret = this.WaitForSingleObject(handle, timeout)?;
583 this.write_scalar(ret, dest)?;
584 }
585 "GetCurrentThread" => {
586 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
587
588 this.write_scalar(
589 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
590 dest,
591 )?;
592 }
593 "SetThreadDescription" => {
594 let [handle, name] = this.check_shim(abi, sys_conv, link_name, args)?;
595
596 let handle = this.read_handle(handle, "SetThreadDescription")?;
597 let name = this.read_wide_str(this.read_pointer(name)?)?;
598
599 let thread = match handle {
600 Handle::Thread(thread) => thread,
601 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
602 _ => this.invalid_handle("SetThreadDescription")?,
603 };
604 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
606 this.write_scalar(Scalar::from_u32(0), dest)?;
607 }
608 "GetThreadDescription" => {
609 let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?;
610
611 let handle = this.read_handle(handle, "GetThreadDescription")?;
612 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
615 Handle::Thread(thread) => thread,
616 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
617 _ => this.invalid_handle("GetThreadDescription")?,
618 };
619 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
621 let name = this.alloc_os_str_as_wide_str(
622 bytes_to_os_str(&name)?,
623 MiriMemoryKind::WinLocal.into(),
624 )?;
625 let name = Scalar::from_maybe_pointer(name, this);
626 let res = Scalar::from_u32(0);
627
628 this.write_scalar(name, &name_ptr)?;
629 this.write_scalar(res, dest)?;
630 }
631
632 "ExitProcess" => {
634 let [code] = this.check_shim(abi, sys_conv, link_name, args)?;
635 let code = this.read_scalar(code)?.to_i32()?;
637 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
638 }
639 "SystemFunction036" => {
640 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
643 let ptr = this.read_pointer(ptr)?;
644 let len = this.read_scalar(len)?.to_u32()?;
645 this.gen_random(ptr, len.into())?;
646 this.write_scalar(Scalar::from_bool(true), dest)?;
647 }
648 "ProcessPrng" => {
649 let [ptr, len] = this.check_shim(abi, sys_conv, link_name, args)?;
651 let ptr = this.read_pointer(ptr)?;
652 let len = this.read_target_usize(len)?;
653 this.gen_random(ptr, len)?;
654 this.write_int(1, dest)?;
655 }
656 "BCryptGenRandom" => {
657 let [algorithm, ptr, len, flags] =
659 this.check_shim(abi, sys_conv, link_name, args)?;
660 let algorithm = this.read_scalar(algorithm)?;
661 let algorithm = algorithm.to_target_usize(this)?;
662 let ptr = this.read_pointer(ptr)?;
663 let len = this.read_scalar(len)?.to_u32()?;
664 let flags = this.read_scalar(flags)?.to_u32()?;
665 match flags {
666 0 => {
667 if algorithm != 0x81 {
668 throw_unsup_format!(
670 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
671 );
672 }
673 }
674 2 => {
675 if algorithm != 0 {
677 throw_unsup_format!(
678 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
679 );
680 }
681 }
682 _ => {
683 throw_unsup_format!(
684 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
685 );
686 }
687 }
688 this.gen_random(ptr, len.into())?;
689 this.write_null(dest)?; }
691 "GetConsoleScreenBufferInfo" => {
692 let [console, buffer_info] = this.check_shim(abi, sys_conv, link_name, args)?;
694 this.read_target_isize(console)?;
695 this.deref_pointer(buffer_info)?;
697 this.write_null(dest)?;
700 }
701 "GetStdHandle" => {
702 let [which] = this.check_shim(abi, sys_conv, link_name, args)?;
703 let which = this.read_scalar(which)?.to_i32()?;
704 this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?;
709 }
710 "CloseHandle" => {
711 let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
712
713 let ret = this.CloseHandle(handle)?;
714
715 this.write_scalar(ret, dest)?;
716 }
717 "GetModuleFileNameW" => {
718 let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?;
719 this.check_no_isolation("`GetModuleFileNameW`")?;
720
721 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
722 let filename = this.read_pointer(filename)?;
723 let size = this.read_scalar(size)?.to_u32()?;
724
725 if handle != Handle::Null {
726 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
727 }
728
729 let path = std::env::current_exe().unwrap();
732 let (all_written, size_needed) =
733 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
734
735 if all_written {
736 this.write_int(size_needed.strict_sub(1), dest)?;
740 } else {
741 this.write_int(size, dest)?;
746 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
747 this.set_last_error(insufficient_buffer)?;
748 }
749 }
750 "FormatMessageW" => {
751 let [flags, module, message_id, language_id, buffer, size, arguments] =
752 this.check_shim(abi, sys_conv, link_name, args)?;
753
754 let flags = this.read_scalar(flags)?.to_u32()?;
755 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
757 let _language_id = this.read_scalar(language_id)?.to_u32()?;
758 let buffer = this.read_pointer(buffer)?;
759 let size = this.read_scalar(size)?.to_u32()?;
760 let _arguments = this.read_pointer(arguments)?;
761
762 if flags != 4096u32 | 512u32 {
765 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
766 }
767
768 let error = this.try_errnum_to_io_error(message_id)?;
769 let formatted = match error {
770 Some(err) => format!("{err}"),
771 None => format!("<unknown error in FormatMessageW: {message_id}>"),
772 };
773 let (complete, length) =
774 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
775 if !complete {
776 throw_unsup_format!("FormatMessageW: buffer not big enough");
779 }
780 this.write_int(length.strict_sub(1), dest)?;
782 }
783
784 "GetProcessHeap" if this.frame_in_std() => {
787 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
788 this.write_int(1, dest)?;
791 }
792 "GetModuleHandleA" if this.frame_in_std() => {
793 #[allow(non_snake_case)]
794 let [_lpModuleName] = this.check_shim(abi, sys_conv, link_name, args)?;
795 this.write_int(1, dest)?;
797 }
798 "SetConsoleTextAttribute" if this.frame_in_std() => {
799 #[allow(non_snake_case)]
800 let [_hConsoleOutput, _wAttribute] =
801 this.check_shim(abi, sys_conv, link_name, args)?;
802 this.write_null(dest)?;
804 }
805 "GetConsoleMode" if this.frame_in_std() => {
806 let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?;
807 this.read_target_isize(console)?;
808 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
809 this.write_null(dest)?;
811 }
812 "GetFileType" if this.frame_in_std() => {
813 #[allow(non_snake_case)]
814 let [_hFile] = this.check_shim(abi, sys_conv, link_name, args)?;
815 this.write_null(dest)?;
817 }
818 "AddVectoredExceptionHandler" if this.frame_in_std() => {
819 #[allow(non_snake_case)]
820 let [_First, _Handler] = this.check_shim(abi, sys_conv, link_name, args)?;
821 this.write_int(1, dest)?;
823 }
824 "SetThreadStackGuarantee" if this.frame_in_std() => {
825 #[allow(non_snake_case)]
826 let [_StackSizeInBytes] = this.check_shim(abi, sys_conv, link_name, args)?;
827 this.write_int(1, dest)?;
829 }
830 "SwitchToThread" if this.frame_in_std() => {
832 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
833
834 this.yield_active_thread();
835
836 this.write_null(dest)?;
838 }
839
840 "_Unwind_RaiseException" => {
841 if this.tcx.sess.target.env != "gnu" {
846 throw_unsup_format!(
847 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
848 );
849 }
850 let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
852 this.handle_miri_start_unwind(payload)?;
853 return interp_ok(EmulateItemResult::NeedsUnwind);
854 }
855
856 _ => return interp_ok(EmulateItemResult::NotSupported),
857 }
858
859 interp_ok(EmulateItemResult::NeedsReturn)
860 }
861}