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::FnAbi;
9use rustc_target::spec::Env;
10
11use self::shims::windows::handle::{Handle, PseudoHandle};
12use crate::shims::os_str::bytes_to_os_str;
13use crate::shims::windows::*;
14use crate::*;
15
16pub fn is_dyn_sym(name: &str) -> bool {
17 matches!(
19 name,
20 "SetThreadDescription" | "GetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle"
21 )
22}
23
24#[cfg(windows)]
25fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
26 interp_ok(path::absolute(path))
28}
29
30#[cfg(unix)]
31#[expect(clippy::get_first, clippy::arithmetic_side_effects)]
32fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
33 use std::sync::LazyLock;
34
35 use rustc_data_structures::fx::FxHashSet;
36
37 let bytes = path.as_os_str().as_encoded_bytes();
45 if bytes.get(0).copied() == Some(b'/')
48 && bytes.get(1).copied() == Some(b'/')
49 && matches!(bytes.get(2), Some(b'.' | b'?'))
50 && bytes.get(3).copied() == Some(b'/')
51 {
52 return interp_ok(Ok(path.into()));
53 };
54 let is_unc = bytes.starts_with(b"//");
55 static MAGIC_FILENAMES: LazyLock<FxHashSet<&'static str>> = LazyLock::new(|| {
57 FxHashSet::from_iter([
58 "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
59 "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
60 ])
61 });
62 if str::from_utf8(bytes).is_ok_and(|s| MAGIC_FILENAMES.contains(&*s.to_ascii_uppercase())) {
63 let mut result: Vec<u8> = b"//./".into();
64 result.extend(bytes);
65 return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
66 }
67 let mut result: Vec<&[u8]> = vec![]; let mut bytes = bytes; let mut stop = false;
72 while !stop {
73 let mut component = match bytes.iter().position(|&b| b == b'/') {
75 Some(pos) => {
76 let (component, tail) = bytes.split_at(pos);
77 bytes = &tail[1..]; component
79 }
80 None => {
81 stop = true;
83 let component = bytes;
84 bytes = &[];
85 component
86 }
87 };
88 if !is_unc && component.eq_ignore_ascii_case(b"NUL") {
92 let mut result: Vec<u8> = b"//./".into();
93 result.extend(component);
94 return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
95 }
96 if component == b".." {
98 let is_root = {
100 result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':'])
102 } || {
103 result.len() == 4 && matches!(result[0], []) && matches!(result[1], [])
105 };
106 if !is_root {
107 result.pop();
108 }
109 continue;
110 }
111 let len = component.len();
114 if !is_unc && len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' {
115 component = &component[..len - 1];
116 }
117 result.push(component);
119 }
120 if result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':']) {
122 result.push(&[]);
123 }
124 let result = result.join(&b'/');
126 interp_ok(path::absolute(bytes_to_os_str(&result)?))
127}
128
129impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
130pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
131 fn emulate_foreign_item_inner(
132 &mut self,
133 link_name: Symbol,
134 abi: &FnAbi<'tcx, Ty<'tcx>>,
135 args: &[OpTy<'tcx>],
136 dest: &MPlaceTy<'tcx>,
137 ) -> InterpResult<'tcx, EmulateItemResult> {
138 let this = self.eval_context_mut();
139
140 match link_name.as_str() {
149 "GetEnvironmentVariableW" => {
151 let [name, buf, size] = this.check_shim_sig(
153 shim_sig!(extern "system" fn(*const _, *mut _, u32) -> u32),
154 link_name,
155 abi,
156 args,
157 )?;
158 let result = this.GetEnvironmentVariableW(name, buf, size)?;
159 this.write_scalar(result, dest)?;
160 }
161 "SetEnvironmentVariableW" => {
162 let [name, value] = this.check_shim_sig(
164 shim_sig!(extern "system" fn(*const _, *const _) -> winapi::BOOL),
165 link_name,
166 abi,
167 args,
168 )?;
169 let result = this.SetEnvironmentVariableW(name, value)?;
170 this.write_scalar(result, dest)?;
171 }
172 "GetEnvironmentStringsW" => {
173 let [] = this.check_shim_sig(
175 shim_sig!(extern "system" fn() -> *mut _),
176 link_name,
177 abi,
178 args,
179 )?;
180 let result = this.GetEnvironmentStringsW()?;
181 this.write_pointer(result, dest)?;
182 }
183 "FreeEnvironmentStringsW" => {
184 let [env_block] = this.check_shim_sig(
186 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
187 link_name,
188 abi,
189 args,
190 )?;
191 let result = this.FreeEnvironmentStringsW(env_block)?;
192 this.write_scalar(result, dest)?;
193 }
194 "GetCurrentDirectoryW" => {
195 let [size, buf] = this.check_shim_sig(
197 shim_sig!(extern "system" fn(u32, *mut _) -> u32),
198 link_name,
199 abi,
200 args,
201 )?;
202 let result = this.GetCurrentDirectoryW(size, buf)?;
203 this.write_scalar(result, dest)?;
204 }
205 "SetCurrentDirectoryW" => {
206 let [path] = this.check_shim_sig(
208 shim_sig!(extern "system" fn(*const _) -> winapi::BOOL),
209 link_name,
210 abi,
211 args,
212 )?;
213 let result = this.SetCurrentDirectoryW(path)?;
214 this.write_scalar(result, dest)?;
215 }
216 "GetUserProfileDirectoryW" => {
217 let [token, buf, size] = this.check_shim_sig(
219 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _, *mut _) -> winapi::BOOL),
220 link_name,
221 abi,
222 args,
223 )?;
224 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
225 this.write_scalar(result, dest)?;
226 }
227 "GetCurrentProcessId" => {
228 let [] = this.check_shim_sig(
230 shim_sig!(extern "system" fn() -> u32),
231 link_name,
232 abi,
233 args,
234 )?;
235 let result = this.GetCurrentProcessId()?;
236 this.write_scalar(result, dest)?;
237 }
238
239 "NtWriteFile" => {
241 let [
242 handle,
243 event,
244 apc_routine,
245 apc_context,
246 io_status_block,
247 buf,
248 n,
249 byte_offset,
250 key,
251 ] = this.check_shim_sig(
252 shim_sig!(
253 extern "system" fn(
254 winapi::HANDLE,
255 winapi::HANDLE,
256 *mut _,
257 *mut _,
258 *mut _,
259 *mut _,
260 u32,
261 *mut _,
262 *mut _,
263 ) -> i32
264 ),
265 link_name,
266 abi,
267 args,
268 )?;
269 this.NtWriteFile(
270 handle,
271 event,
272 apc_routine,
273 apc_context,
274 io_status_block,
275 buf,
276 n,
277 byte_offset,
278 key,
279 dest,
280 )?;
281 }
282 "NtReadFile" => {
283 let [
284 handle,
285 event,
286 apc_routine,
287 apc_context,
288 io_status_block,
289 buf,
290 n,
291 byte_offset,
292 key,
293 ] = this.check_shim_sig(
294 shim_sig!(
295 extern "system" fn(
296 winapi::HANDLE,
297 winapi::HANDLE,
298 *mut _,
299 *mut _,
300 *mut _,
301 *mut _,
302 u32,
303 *mut _,
304 *mut _,
305 ) -> i32
306 ),
307 link_name,
308 abi,
309 args,
310 )?;
311 this.NtReadFile(
312 handle,
313 event,
314 apc_routine,
315 apc_context,
316 io_status_block,
317 buf,
318 n,
319 byte_offset,
320 key,
321 dest,
322 )?;
323 }
324 "GetFullPathNameW" => {
325 let [filename, size, buffer, filepart] = this.check_shim_sig(
327 shim_sig!(extern "system" fn(*const _, u32, *mut _, *mut _) -> u32),
328 link_name,
329 abi,
330 args,
331 )?;
332 this.check_no_isolation("`GetFullPathNameW`")?;
333
334 let filename = this.read_pointer(filename)?;
335 let size = this.read_scalar(size)?.to_u32()?;
336 let buffer = this.read_pointer(buffer)?;
337 let filepart = this.read_pointer(filepart)?;
338
339 if !this.ptr_is_null(filepart)? {
340 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
341 }
342
343 let filename = this.read_path_from_wide_str(filename)?;
344 let result = match win_get_full_path_name(&filename)? {
345 Err(err) => {
346 this.set_last_error(err)?;
347 Scalar::from_u32(0) }
349 Ok(abs_filename) => {
350 Scalar::from_u32(helpers::windows_check_buffer_size(
351 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
352 ))
353 }
356 };
357 this.write_scalar(result, dest)?;
358 }
359 "CreateFileW" => {
360 let [
361 file_name,
362 desired_access,
363 share_mode,
364 security_attributes,
365 creation_disposition,
366 flags_and_attributes,
367 template_file,
368 ] = this.check_shim_sig(
369 shim_sig!(
370 extern "system" fn(
371 *const _,
372 u32,
373 u32,
374 *mut _,
375 u32,
376 u32,
377 winapi::HANDLE,
378 ) -> winapi::HANDLE
379 ),
380 link_name,
381 abi,
382 args,
383 )?;
384 let handle = this.CreateFileW(
385 file_name,
386 desired_access,
387 share_mode,
388 security_attributes,
389 creation_disposition,
390 flags_and_attributes,
391 template_file,
392 )?;
393 this.write_scalar(handle.to_scalar(this), dest)?;
394 }
395 "GetFileInformationByHandle" => {
396 let [handle, info] = this.check_shim_sig(
397 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
398 link_name,
399 abi,
400 args,
401 )?;
402 let res = this.GetFileInformationByHandle(handle, info)?;
403 this.write_scalar(res, dest)?;
404 }
405 "SetFileInformationByHandle" => {
406 let [handle, class, info, size] = this.check_shim_sig(
407 shim_sig!(
408 extern "system" fn(
409 winapi::HANDLE,
410 winapi::FILE_INFO_BY_HANDLE_CLASS,
411 *mut _,
412 u32,
413 ) -> winapi::BOOL
414 ),
415 link_name,
416 abi,
417 args,
418 )?;
419 let res = this.SetFileInformationByHandle(handle, class, info, size)?;
420 this.write_scalar(res, dest)?;
421 }
422 "FlushFileBuffers" => {
423 let [handle] = this.check_shim_sig(
424 shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
425 link_name,
426 abi,
427 args,
428 )?;
429 let res = this.FlushFileBuffers(handle)?;
430 this.write_scalar(res, dest)?;
431 }
432 "DeleteFileW" => {
433 let [file_name] = this.check_shim_sig(
434 shim_sig!(extern "system" fn(*const _) -> winapi::BOOL),
435 link_name,
436 abi,
437 args,
438 )?;
439 let res = this.DeleteFileW(file_name)?;
440 this.write_scalar(res, dest)?;
441 }
442 "SetFilePointerEx" => {
443 let [file, distance_to_move, new_file_pointer, move_method] = this.check_shim_sig(
444 shim_sig!(extern "system" fn(winapi::HANDLE, i64, *mut _, u32) -> winapi::BOOL),
446 link_name,
447 abi,
448 args,
449 )?;
450 let res =
451 this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
452 this.write_scalar(res, dest)?;
453 }
454 "MoveFileExW" => {
455 let [existing_name, new_name, flags] = this.check_shim_sig(
456 shim_sig!(extern "system" fn(*const _, *const _, u32) -> winapi::BOOL),
457 link_name,
458 abi,
459 args,
460 )?;
461 let res = this.MoveFileExW(existing_name, new_name, flags)?;
462 this.write_scalar(res, dest)?;
463 }
464
465 "HeapAlloc" => {
467 let [handle, flags, size] = this.check_shim_sig(
469 shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *mut _),
470 link_name,
471 abi,
472 args,
473 )?;
474 this.read_target_isize(handle)?;
475 let flags = this.read_scalar(flags)?.to_u32()?;
476 let size = this.read_target_usize(size)?;
477 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
478 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
479 AllocInit::Zero
480 } else {
481 AllocInit::Uninit
482 };
483 let align = this.tcx.pointer_size().bytes().strict_mul(2);
486 let ptr = this.allocate_ptr(
487 Size::from_bytes(size),
488 Align::from_bytes(align).unwrap(),
489 MiriMemoryKind::WinHeap.into(),
490 init,
491 )?;
492 this.write_pointer(ptr, dest)?;
493 }
494 "HeapFree" => {
495 let [handle, flags, ptr] = this.check_shim_sig(
497 shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _) -> winapi::BOOL),
498 link_name,
499 abi,
500 args,
501 )?;
502 this.read_target_isize(handle)?;
503 this.read_scalar(flags)?.to_u32()?;
504 let ptr = this.read_pointer(ptr)?;
505 if !this.ptr_is_null(ptr)? {
508 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
509 }
510 this.write_scalar(Scalar::from_i32(1), dest)?;
511 }
512 "HeapReAlloc" => {
513 let [handle, flags, old_ptr, size] = this.check_shim_sig(
515 shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _, usize) -> *mut _),
516 link_name,
517 abi,
518 args,
519 )?;
520 this.read_target_isize(handle)?;
521 this.read_scalar(flags)?.to_u32()?;
522 let old_ptr = this.read_pointer(old_ptr)?;
523 let size = this.read_target_usize(size)?;
524 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
529 old_ptr,
530 None,
531 Size::from_bytes(size),
532 Align::from_bytes(align).unwrap(),
533 MiriMemoryKind::WinHeap.into(),
534 AllocInit::Uninit,
535 )?;
536 this.write_pointer(new_ptr, dest)?;
537 }
538 "LocalFree" => {
539 let [ptr] = this.check_shim_sig(
541 shim_sig!(extern "system" fn(winapi::HLOCAL) -> winapi::HLOCAL),
542 link_name,
543 abi,
544 args,
545 )?;
546 let ptr = this.read_pointer(ptr)?;
547 if !this.ptr_is_null(ptr)? {
550 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
551 }
552 this.write_null(dest)?;
553 }
554
555 "SetLastError" => {
557 let [error] = this.check_shim_sig(
558 shim_sig!(extern "system" fn(u32) -> ()),
559 link_name,
560 abi,
561 args,
562 )?;
563 let error = this.read_scalar(error)?;
564 this.set_last_error(error)?;
565 }
566 "GetLastError" => {
567 let [] = this.check_shim_sig(
568 shim_sig!(extern "system" fn() -> u32),
569 link_name,
570 abi,
571 args,
572 )?;
573 let last_error = this.get_last_error()?;
574 this.write_scalar(last_error, dest)?;
575 }
576 "RtlNtStatusToDosError" => {
577 let [status] = this.check_shim_sig(
578 shim_sig!(extern "system" fn(i32) -> u32),
579 link_name,
580 abi,
581 args,
582 )?;
583 let status = this.read_scalar(status)?.to_u32()?;
584 let err = match status {
585 0xC00000A2 => 19,
587 0xC0000098 => 1006,
589 0xC000007F => 112,
591 0xC0000185 => 1117,
593 0xC0000022 => 5,
595 _ => 317,
597 };
598 this.write_scalar(Scalar::from_i32(err), dest)?;
599 }
600
601 "GetSystemInfo" => {
603 let [system_info] = this.check_shim_sig(
606 shim_sig!(extern "system" fn(*mut _) -> ()),
607 link_name,
608 abi,
609 args,
610 )?;
611 let system_info =
612 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
613 this.write_bytes_ptr(
615 system_info.ptr(),
616 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
617 )?;
618 this.write_int_fields_named(
620 &[
621 ("dwPageSize", this.machine.page_size.into()),
622 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
623 ],
624 &system_info,
625 )?;
626 }
627
628 "TlsAlloc" => {
630 let [] = this.check_shim_sig(
634 shim_sig!(extern "system" fn() -> u32),
635 link_name,
636 abi,
637 args,
638 )?;
639 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
640 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
641 }
642 "TlsGetValue" => {
643 let [key] = this.check_shim_sig(
644 shim_sig!(extern "system" fn(u32) -> *mut _),
645 link_name,
646 abi,
647 args,
648 )?;
649 let key = u128::from(this.read_scalar(key)?.to_u32()?);
650 let active_thread = this.active_thread();
651 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
652 this.write_scalar(ptr, dest)?;
653 }
654 "TlsSetValue" => {
655 let [key, new_ptr] = this.check_shim_sig(
656 shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL),
657 link_name,
658 abi,
659 args,
660 )?;
661 let key = u128::from(this.read_scalar(key)?.to_u32()?);
662 let active_thread = this.active_thread();
663 let new_data = this.read_scalar(new_ptr)?;
664 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
665
666 this.write_int(1, dest)?;
668 }
669 "TlsFree" => {
670 let [key] = this.check_shim_sig(
671 shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
672 link_name,
673 abi,
674 args,
675 )?;
676 let key = u128::from(this.read_scalar(key)?.to_u32()?);
677 this.machine.tls.delete_tls_key(key)?;
678
679 this.write_int(1, dest)?;
681 }
682
683 "GetCommandLineW" => {
685 let [] = this.check_shim_sig(
687 shim_sig!(extern "system" fn() -> *mut _),
688 link_name,
689 abi,
690 args,
691 )?;
692 this.write_pointer(
693 this.machine.cmd_line.expect("machine must be initialized"),
694 dest,
695 )?;
696 }
697
698 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
700 let [filetime] = this.check_shim_sig(
702 shim_sig!(extern "system" fn(*mut _) -> ()),
703 link_name,
704 abi,
705 args,
706 )?;
707 this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?;
708 }
709 "QueryPerformanceCounter" => {
710 let [performance_count] = this.check_shim_sig(
712 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
713 link_name,
714 abi,
715 args,
716 )?;
717 let result = this.QueryPerformanceCounter(performance_count)?;
718 this.write_scalar(result, dest)?;
719 }
720 "QueryPerformanceFrequency" => {
721 let [frequency] = this.check_shim_sig(
723 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
724 link_name,
725 abi,
726 args,
727 )?;
728 let result = this.QueryPerformanceFrequency(frequency)?;
729 this.write_scalar(result, dest)?;
730 }
731 "Sleep" => {
732 let [timeout] = this.check_shim_sig(
734 shim_sig!(extern "system" fn(u32) -> ()),
735 link_name,
736 abi,
737 args,
738 )?;
739
740 this.Sleep(timeout)?;
741 }
742 "CreateWaitableTimerExW" => {
743 let [attributes, name, flags, access] = this.check_shim_sig(
745 shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE),
746 link_name,
747 abi,
748 args,
749 )?;
750 this.read_pointer(attributes)?;
751 this.read_pointer(name)?;
752 this.read_scalar(flags)?.to_u32()?;
753 this.read_scalar(access)?.to_u32()?;
754 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
756 this.set_last_error(not_supported)?;
757 this.write_null(dest)?;
758 }
759
760 "InitOnceBeginInitialize" => {
762 let [ptr, flags, pending, context] = this.check_shim_sig(
763 shim_sig!(extern "system" fn(*mut _, u32, *mut _, *mut _) -> winapi::BOOL),
764 link_name,
765 abi,
766 args,
767 )?;
768 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
769 }
770 "InitOnceComplete" => {
771 let [ptr, flags, context] = this.check_shim_sig(
772 shim_sig!(extern "system" fn(*mut _, u32, *mut _) -> winapi::BOOL),
773 link_name,
774 abi,
775 args,
776 )?;
777 let result = this.InitOnceComplete(ptr, flags, context)?;
778 this.write_scalar(result, dest)?;
779 }
780 "WaitOnAddress" => {
781 let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig(
783 shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL),
785 link_name,
786 abi,
787 args,
788 )?;
789
790 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
791 }
792 "WakeByAddressSingle" => {
793 let [ptr_op] = this.check_shim_sig(
795 shim_sig!(extern "system" fn(*mut _) -> ()),
796 link_name,
797 abi,
798 args,
799 )?;
800
801 this.WakeByAddressSingle(ptr_op)?;
802 }
803 "WakeByAddressAll" => {
804 let [ptr_op] = this.check_shim_sig(
806 shim_sig!(extern "system" fn(*mut _) -> ()),
807 link_name,
808 abi,
809 args,
810 )?;
811
812 this.WakeByAddressAll(ptr_op)?;
813 }
814
815 "GetProcAddress" => {
817 let [module, proc_name] = this.check_shim_sig(
819 shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC),
820 link_name,
821 abi,
822 args,
823 )?;
824 this.read_target_isize(module)?;
825 let name = this.read_c_str(this.read_pointer(proc_name)?)?;
826 if let Ok(name) = str::from_utf8(name)
827 && is_dyn_sym(name)
828 {
829 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
830 this.write_pointer(ptr, dest)?;
831 } else {
832 this.write_null(dest)?;
833 }
834 }
835
836 "CreateThread" => {
838 let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig(
839 shim_sig!(
840 extern "system" fn(
841 *mut _,
842 usize,
843 *mut _,
844 *mut _,
845 u32,
846 *mut _,
847 ) -> winapi::HANDLE
848 ),
849 link_name,
850 abi,
851 args,
852 )?;
853
854 let thread_id =
855 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
856
857 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
858 }
859 "WaitForSingleObject" => {
860 let [handle, timeout] = this.check_shim_sig(
861 shim_sig!(extern "system" fn(winapi::HANDLE, u32) -> u32),
862 link_name,
863 abi,
864 args,
865 )?;
866
867 this.WaitForSingleObject(handle, timeout, dest)?;
868 }
869 "GetCurrentProcess" => {
870 let [] = this.check_shim_sig(
871 shim_sig!(extern "system" fn() -> winapi::HANDLE),
872 link_name,
873 abi,
874 args,
875 )?;
876
877 this.write_scalar(
878 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
879 dest,
880 )?;
881 }
882 "GetCurrentThread" => {
883 let [] = this.check_shim_sig(
884 shim_sig!(extern "system" fn() -> winapi::HANDLE),
885 link_name,
886 abi,
887 args,
888 )?;
889
890 this.write_scalar(
891 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
892 dest,
893 )?;
894 }
895 "SetThreadDescription" => {
896 let [handle, name] = this.check_shim_sig(
897 shim_sig!(extern "system" fn(winapi::HANDLE, *const _) -> i32),
898 link_name,
899 abi,
900 args,
901 )?;
902
903 let handle = this.read_handle(handle, "SetThreadDescription")?;
904 let name = this.read_wide_str(this.read_pointer(name)?)?;
905
906 let thread = match handle {
907 Handle::Thread(thread) => thread,
908 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
909 _ => this.invalid_handle("SetThreadDescription")?,
910 };
911 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
913 this.write_scalar(Scalar::from_u32(0), dest)?;
914 }
915 "GetThreadDescription" => {
916 let [handle, name_ptr] = this.check_shim_sig(
917 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> i32),
918 link_name,
919 abi,
920 args,
921 )?;
922
923 let handle = this.read_handle(handle, "GetThreadDescription")?;
924 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
927 Handle::Thread(thread) => thread,
928 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
929 _ => this.invalid_handle("GetThreadDescription")?,
930 };
931 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
933 let name = this.alloc_os_str_as_wide_str(
934 bytes_to_os_str(&name)?,
935 MiriMemoryKind::WinLocal.into(),
936 )?;
937 let name = Scalar::from_maybe_pointer(name, this);
938 let res = Scalar::from_u32(0);
939
940 this.write_scalar(name, &name_ptr)?;
941 this.write_scalar(res, dest)?;
942 }
943 "GetThreadId" => {
944 let [handle] = this.check_shim_sig(
945 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
946 link_name,
947 abi,
948 args,
949 )?;
950 let handle = this.read_handle(handle, "GetThreadId")?;
951 let thread = match handle {
952 Handle::Thread(thread) => thread,
953 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
954 _ => this.invalid_handle("GetThreadDescription")?,
955 };
956 let tid = this.get_tid(thread);
957 this.write_scalar(Scalar::from_u32(tid), dest)?;
958 }
959 "GetCurrentThreadId" => {
960 let [] = this.check_shim_sig(
961 shim_sig!(extern "system" fn() -> u32),
962 link_name,
963 abi,
964 args,
965 )?;
966 let thread = this.active_thread();
967 let tid = this.get_tid(thread);
968 this.write_scalar(Scalar::from_u32(tid), dest)?;
969 }
970
971 "ExitProcess" => {
973 let [code] = this.check_shim_sig(
975 shim_sig!(extern "system" fn(u32) -> ()),
976 link_name,
977 abi,
978 args,
979 )?;
980 let code = this.read_scalar(code)?.to_i32()?;
982 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
983 }
984 "SystemFunction036" => {
985 let [ptr, len] = this.check_shim_sig(
988 shim_sig!(extern "system" fn(*mut _, u32) -> u8),
990 link_name,
991 abi,
992 args,
993 )?;
994 let ptr = this.read_pointer(ptr)?;
995 let len = this.read_scalar(len)?.to_u32()?;
996 this.gen_random(ptr, len.into())?;
997 this.write_scalar(Scalar::from_bool(true), dest)?;
998 }
999 "ProcessPrng" => {
1000 let [ptr, len] = this.check_shim_sig(
1003 shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL),
1004 link_name,
1005 abi,
1006 args,
1007 )?;
1008 let ptr = this.read_pointer(ptr)?;
1009 let len = this.read_target_usize(len)?;
1010 this.gen_random(ptr, len)?;
1011 this.write_int(1, dest)?;
1012 }
1013 "BCryptGenRandom" => {
1014 let [algorithm, ptr, len, flags] = this.check_shim_sig(
1016 shim_sig!(extern "system" fn(*mut _, *mut _, u32, u32) -> i32),
1017 link_name,
1018 abi,
1019 args,
1020 )?;
1021 let algorithm = this.read_scalar(algorithm)?;
1022 let algorithm = algorithm.to_target_usize(this)?;
1023 let ptr = this.read_pointer(ptr)?;
1024 let len = this.read_scalar(len)?.to_u32()?;
1025 let flags = this.read_scalar(flags)?.to_u32()?;
1026 match flags {
1027 0 => {
1028 if algorithm != 0x81 {
1029 throw_unsup_format!(
1031 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
1032 );
1033 }
1034 }
1035 2 => {
1036 if algorithm != 0 {
1038 throw_unsup_format!(
1039 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
1040 );
1041 }
1042 }
1043 _ => {
1044 throw_unsup_format!(
1045 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
1046 );
1047 }
1048 }
1049 this.gen_random(ptr, len.into())?;
1050 this.write_null(dest)?; }
1052 "GetConsoleScreenBufferInfo" => {
1053 let [console, buffer_info] = this.check_shim_sig(
1056 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1057 link_name,
1058 abi,
1059 args,
1060 )?;
1061 this.read_target_isize(console)?;
1062 this.deref_pointer(buffer_info)?;
1064 this.write_null(dest)?;
1067 }
1068 "GetStdHandle" => {
1069 let [which] = this.check_shim_sig(
1071 shim_sig!(extern "system" fn(u32) -> winapi::HANDLE),
1072 link_name,
1073 abi,
1074 args,
1075 )?;
1076 let res = this.GetStdHandle(which)?;
1077 this.write_scalar(res, dest)?;
1078 }
1079 "DuplicateHandle" => {
1080 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
1081 this.check_shim_sig(
1082 shim_sig!(
1083 extern "system" fn(
1084 winapi::HANDLE,
1085 winapi::HANDLE,
1086 winapi::HANDLE,
1087 *mut _,
1088 u32,
1089 winapi::BOOL,
1090 u32,
1091 ) -> winapi::BOOL
1092 ),
1093 link_name,
1094 abi,
1095 args,
1096 )?;
1097 let res = this.DuplicateHandle(
1098 src_proc,
1099 src_handle,
1100 target_proc,
1101 target_handle,
1102 access,
1103 inherit,
1104 options,
1105 )?;
1106 this.write_scalar(res, dest)?;
1107 }
1108 "CloseHandle" => {
1109 let [handle] = this.check_shim_sig(
1110 shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
1111 link_name,
1112 abi,
1113 args,
1114 )?;
1115
1116 let ret = this.CloseHandle(handle)?;
1117
1118 this.write_scalar(ret, dest)?;
1119 }
1120 "GetModuleFileNameW" => {
1121 let [handle, filename, size] = this.check_shim_sig(
1123 shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32),
1124 link_name,
1125 abi,
1126 args,
1127 )?;
1128 this.check_no_isolation("`GetModuleFileNameW`")?;
1129
1130 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
1131 let filename = this.read_pointer(filename)?;
1132 let size = this.read_scalar(size)?.to_u32()?;
1133
1134 if handle != Handle::Null {
1135 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
1136 }
1137
1138 let path = std::env::current_exe().unwrap();
1141 let (all_written, size_needed) =
1142 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
1143
1144 if all_written {
1145 this.write_int(size_needed.strict_sub(1), dest)?;
1149 } else {
1150 this.write_int(size, dest)?;
1155 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
1156 this.set_last_error(insufficient_buffer)?;
1157 }
1158 }
1159 "FormatMessageW" => {
1160 let [flags, module, message_id, language_id, buffer, size, arguments] = this
1162 .check_shim_sig(
1163 shim_sig!(
1164 extern "system" fn(u32, *const _, u32, u32, *mut _, u32, *mut _) -> u32
1165 ),
1166 link_name,
1167 abi,
1168 args,
1169 )?;
1170
1171 let flags = this.read_scalar(flags)?.to_u32()?;
1172 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
1174 let _language_id = this.read_scalar(language_id)?.to_u32()?;
1175 let buffer = this.read_pointer(buffer)?;
1176 let size = this.read_scalar(size)?.to_u32()?;
1177 let _arguments = this.read_pointer(arguments)?;
1178
1179 if flags != 4096u32 | 512u32 {
1182 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
1183 }
1184
1185 let error = this.try_errnum_to_io_error(message_id)?;
1186 let formatted = match error {
1187 Some(err) => format!("{err}"),
1188 None => format!("<unknown error in FormatMessageW: {message_id}>"),
1189 };
1190 let (complete, length) =
1191 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
1192 if !complete {
1193 throw_unsup_format!("FormatMessageW: buffer not big enough");
1196 }
1197 this.write_int(length.strict_sub(1), dest)?;
1199 }
1200
1201 "_Unwind_RaiseException" => {
1202 if this.tcx.sess.target.env != Env::Gnu {
1208 throw_unsup_format!(
1209 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
1210 );
1211 }
1212 let [payload] = this.check_shim_sig(
1214 shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code),
1215 link_name,
1216 abi,
1217 args,
1218 )?;
1219 this.handle_miri_start_unwind(payload)?;
1220 return interp_ok(EmulateItemResult::NeedsUnwind);
1221 }
1222
1223 "GetProcessHeap" if this.frame_in_std() => {
1226 let [] = this.check_shim_sig(
1227 shim_sig!(extern "system" fn() -> winapi::HANDLE),
1228 link_name,
1229 abi,
1230 args,
1231 )?;
1232 this.write_int(1, dest)?;
1235 }
1236 "GetModuleHandleA" if this.frame_in_std() => {
1237 let [_module_name] = this.check_shim_sig(
1238 shim_sig!(extern "system" fn(*const _) -> winapi::HMODULE),
1239 link_name,
1240 abi,
1241 args,
1242 )?;
1243 this.write_int(1, dest)?;
1245 }
1246 "SetConsoleTextAttribute" if this.frame_in_std() => {
1247 let [_console_output, _attribute] = this.check_shim_sig(
1248 shim_sig!(extern "system" fn(winapi::HANDLE, u16) -> winapi::BOOL),
1249 link_name,
1250 abi,
1251 args,
1252 )?;
1253 this.write_null(dest)?;
1255 }
1256 "GetConsoleMode" if this.frame_in_std() => {
1257 let [console, mode] = this.check_shim_sig(
1258 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1259 link_name,
1260 abi,
1261 args,
1262 )?;
1263 this.read_target_isize(console)?;
1264 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
1265 this.write_null(dest)?;
1267 }
1268 "GetFileType" if this.frame_in_std() => {
1269 let [_file] = this.check_shim_sig(
1270 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
1271 link_name,
1272 abi,
1273 args,
1274 )?;
1275 this.write_null(dest)?;
1277 }
1278 "AddVectoredExceptionHandler" if this.frame_in_std() => {
1279 let [_first, _handler] = this.check_shim_sig(
1280 shim_sig!(extern "system" fn(u32, *mut _) -> *mut _),
1281 link_name,
1282 abi,
1283 args,
1284 )?;
1285 this.write_int(1, dest)?;
1287 }
1288 "SetThreadStackGuarantee" if this.frame_in_std() => {
1289 let [_stack_size_in_bytes] = this.check_shim_sig(
1290 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
1291 link_name,
1292 abi,
1293 args,
1294 )?;
1295 this.write_int(1, dest)?;
1297 }
1298 "SwitchToThread" if this.frame_in_std() => {
1300 let [] = this.check_shim_sig(
1301 shim_sig!(extern "system" fn() -> winapi::BOOL),
1302 link_name,
1303 abi,
1304 args,
1305 )?;
1306
1307 this.yield_active_thread();
1308
1309 this.write_null(dest)?;
1311 }
1312
1313 _ => return interp_ok(EmulateItemResult::NotSupported),
1314 }
1315
1316 interp_ok(EmulateItemResult::NeedsReturn)
1317 }
1318}