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 "GetTempPathW" => {
239 let [bufferlength, buffer] = this.check_shim_sig(
241 shim_sig!(extern "system" fn(u32, *mut _) -> u32),
242 link_name,
243 abi,
244 args,
245 )?;
246 let result = this.GetTempPathW(bufferlength, buffer)?;
247 this.write_scalar(result, dest)?;
248 }
249
250 "NtWriteFile" => {
252 let [
253 handle,
254 event,
255 apc_routine,
256 apc_context,
257 io_status_block,
258 buf,
259 n,
260 byte_offset,
261 key,
262 ] = this.check_shim_sig(
263 shim_sig!(
264 extern "system" fn(
265 winapi::HANDLE,
266 winapi::HANDLE,
267 *mut _,
268 *mut _,
269 *mut _,
270 *mut _,
271 u32,
272 *mut _,
273 *mut _,
274 ) -> i32
275 ),
276 link_name,
277 abi,
278 args,
279 )?;
280 this.NtWriteFile(
281 handle,
282 event,
283 apc_routine,
284 apc_context,
285 io_status_block,
286 buf,
287 n,
288 byte_offset,
289 key,
290 dest,
291 )?;
292 }
293 "NtReadFile" => {
294 let [
295 handle,
296 event,
297 apc_routine,
298 apc_context,
299 io_status_block,
300 buf,
301 n,
302 byte_offset,
303 key,
304 ] = this.check_shim_sig(
305 shim_sig!(
306 extern "system" fn(
307 winapi::HANDLE,
308 winapi::HANDLE,
309 *mut _,
310 *mut _,
311 *mut _,
312 *mut _,
313 u32,
314 *mut _,
315 *mut _,
316 ) -> i32
317 ),
318 link_name,
319 abi,
320 args,
321 )?;
322 this.NtReadFile(
323 handle,
324 event,
325 apc_routine,
326 apc_context,
327 io_status_block,
328 buf,
329 n,
330 byte_offset,
331 key,
332 dest,
333 )?;
334 }
335 "GetFullPathNameW" => {
336 let [filename, size, buffer, filepart] = this.check_shim_sig(
338 shim_sig!(extern "system" fn(*const _, u32, *mut _, *mut _) -> u32),
339 link_name,
340 abi,
341 args,
342 )?;
343 this.check_no_isolation("`GetFullPathNameW`")?;
344
345 let filename = this.read_pointer(filename)?;
346 let size = this.read_scalar(size)?.to_u32()?;
347 let buffer = this.read_pointer(buffer)?;
348 let filepart = this.read_pointer(filepart)?;
349
350 if !this.ptr_is_null(filepart)? {
351 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
352 }
353
354 let filename = this.read_path_from_wide_str(filename)?;
355 let result = match win_get_full_path_name(&filename)? {
356 Err(err) => {
357 this.set_last_error(err)?;
358 Scalar::from_u32(0) }
360 Ok(abs_filename) => {
361 Scalar::from_u32(helpers::windows_check_buffer_size(
362 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
363 ))
364 }
367 };
368 this.write_scalar(result, dest)?;
369 }
370 "CreateFileW" => {
371 let [
372 file_name,
373 desired_access,
374 share_mode,
375 security_attributes,
376 creation_disposition,
377 flags_and_attributes,
378 template_file,
379 ] = this.check_shim_sig(
380 shim_sig!(
381 extern "system" fn(
382 *const _,
383 u32,
384 u32,
385 *mut _,
386 u32,
387 u32,
388 winapi::HANDLE,
389 ) -> winapi::HANDLE
390 ),
391 link_name,
392 abi,
393 args,
394 )?;
395 let handle = this.CreateFileW(
396 file_name,
397 desired_access,
398 share_mode,
399 security_attributes,
400 creation_disposition,
401 flags_and_attributes,
402 template_file,
403 )?;
404 this.write_scalar(handle.to_scalar(this), dest)?;
405 }
406 "GetFileInformationByHandle" => {
407 let [handle, info] = this.check_shim_sig(
408 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
409 link_name,
410 abi,
411 args,
412 )?;
413 let res = this.GetFileInformationByHandle(handle, info)?;
414 this.write_scalar(res, dest)?;
415 }
416 "SetFileInformationByHandle" => {
417 let [handle, class, info, size] = this.check_shim_sig(
418 shim_sig!(
419 extern "system" fn(
420 winapi::HANDLE,
421 winapi::FILE_INFO_BY_HANDLE_CLASS,
422 *mut _,
423 u32,
424 ) -> winapi::BOOL
425 ),
426 link_name,
427 abi,
428 args,
429 )?;
430 let res = this.SetFileInformationByHandle(handle, class, info, size)?;
431 this.write_scalar(res, dest)?;
432 }
433 "FlushFileBuffers" => {
434 let [handle] = this.check_shim_sig(
435 shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
436 link_name,
437 abi,
438 args,
439 )?;
440 let res = this.FlushFileBuffers(handle)?;
441 this.write_scalar(res, dest)?;
442 }
443 "DeleteFileW" => {
444 let [file_name] = this.check_shim_sig(
445 shim_sig!(extern "system" fn(*const _) -> winapi::BOOL),
446 link_name,
447 abi,
448 args,
449 )?;
450 let res = this.DeleteFileW(file_name)?;
451 this.write_scalar(res, dest)?;
452 }
453 "SetFilePointerEx" => {
454 let [file, distance_to_move, new_file_pointer, move_method] = this.check_shim_sig(
455 shim_sig!(extern "system" fn(winapi::HANDLE, i64, *mut _, u32) -> winapi::BOOL),
457 link_name,
458 abi,
459 args,
460 )?;
461 let res =
462 this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
463 this.write_scalar(res, dest)?;
464 }
465 "MoveFileExW" => {
466 let [existing_name, new_name, flags] = this.check_shim_sig(
467 shim_sig!(extern "system" fn(*const _, *const _, u32) -> winapi::BOOL),
468 link_name,
469 abi,
470 args,
471 )?;
472 let res = this.MoveFileExW(existing_name, new_name, flags)?;
473 this.write_scalar(res, dest)?;
474 }
475
476 "HeapAlloc" => {
478 let [handle, flags, size] = this.check_shim_sig(
480 shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *mut _),
481 link_name,
482 abi,
483 args,
484 )?;
485 this.read_target_isize(handle)?;
486 let flags = this.read_scalar(flags)?.to_u32()?;
487 let size = this.read_target_usize(size)?;
488 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
489 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
490 AllocInit::Zero
491 } else {
492 AllocInit::Uninit
493 };
494 let align = this.tcx.pointer_size().bytes().strict_mul(2);
497 let ptr = this.allocate_ptr(
498 Size::from_bytes(size),
499 Align::from_bytes(align).unwrap(),
500 MiriMemoryKind::WinHeap.into(),
501 init,
502 )?;
503 this.write_pointer(ptr, dest)?;
504 }
505 "HeapFree" => {
506 let [handle, flags, ptr] = this.check_shim_sig(
508 shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _) -> winapi::BOOL),
509 link_name,
510 abi,
511 args,
512 )?;
513 this.read_target_isize(handle)?;
514 this.read_scalar(flags)?.to_u32()?;
515 let ptr = this.read_pointer(ptr)?;
516 if !this.ptr_is_null(ptr)? {
519 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
520 }
521 this.write_scalar(Scalar::from_i32(1), dest)?;
522 }
523 "HeapReAlloc" => {
524 let [handle, flags, old_ptr, size] = this.check_shim_sig(
526 shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _, usize) -> *mut _),
527 link_name,
528 abi,
529 args,
530 )?;
531 this.read_target_isize(handle)?;
532 this.read_scalar(flags)?.to_u32()?;
533 let old_ptr = this.read_pointer(old_ptr)?;
534 let size = this.read_target_usize(size)?;
535 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
540 old_ptr,
541 None,
542 Size::from_bytes(size),
543 Align::from_bytes(align).unwrap(),
544 MiriMemoryKind::WinHeap.into(),
545 AllocInit::Uninit,
546 )?;
547 this.write_pointer(new_ptr, dest)?;
548 }
549 "LocalFree" => {
550 let [ptr] = this.check_shim_sig(
552 shim_sig!(extern "system" fn(winapi::HLOCAL) -> winapi::HLOCAL),
553 link_name,
554 abi,
555 args,
556 )?;
557 let ptr = this.read_pointer(ptr)?;
558 if !this.ptr_is_null(ptr)? {
561 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
562 }
563 this.write_null(dest)?;
564 }
565
566 "SetLastError" => {
568 let [error] = this.check_shim_sig(
569 shim_sig!(extern "system" fn(u32) -> ()),
570 link_name,
571 abi,
572 args,
573 )?;
574 let error = this.read_scalar(error)?;
575 this.set_last_error(error)?;
576 }
577 "GetLastError" => {
578 let [] = this.check_shim_sig(
579 shim_sig!(extern "system" fn() -> u32),
580 link_name,
581 abi,
582 args,
583 )?;
584 let last_error = this.get_last_error()?;
585 this.write_scalar(last_error, dest)?;
586 }
587 "RtlNtStatusToDosError" => {
588 let [status] = this.check_shim_sig(
589 shim_sig!(extern "system" fn(i32) -> u32),
590 link_name,
591 abi,
592 args,
593 )?;
594 let status = this.read_scalar(status)?.to_u32()?;
595 let err = match status {
596 0xC00000A2 => 19,
598 0xC0000098 => 1006,
600 0xC000007F => 112,
602 0xC0000185 => 1117,
604 0xC0000022 => 5,
606 _ => 317,
608 };
609 this.write_scalar(Scalar::from_i32(err), dest)?;
610 }
611
612 "GetSystemInfo" => {
614 let [system_info] = this.check_shim_sig(
617 shim_sig!(extern "system" fn(*mut _) -> ()),
618 link_name,
619 abi,
620 args,
621 )?;
622 let system_info =
623 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
624 this.write_bytes_ptr(
626 system_info.ptr(),
627 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
628 )?;
629 this.write_int_fields_named(
631 &[
632 ("dwPageSize", this.machine.page_size.into()),
633 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
634 ],
635 &system_info,
636 )?;
637 }
638
639 "TlsAlloc" => {
641 let [] = this.check_shim_sig(
646 shim_sig!(extern "system" fn() -> u32),
647 link_name,
648 abi,
649 args,
650 )?;
651 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
652 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
653 }
654 "TlsGetValue" => {
655 let [key] = this.check_shim_sig(
657 shim_sig!(extern "system" fn(u32) -> *mut _),
658 link_name,
659 abi,
660 args,
661 )?;
662 let key = u128::from(this.read_scalar(key)?.to_u32()?);
663 let active_thread = this.active_thread();
664 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
665 this.write_scalar(ptr, dest)?;
666 }
667 "TlsSetValue" => {
668 let [key, new_ptr] = this.check_shim_sig(
670 shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL),
671 link_name,
672 abi,
673 args,
674 )?;
675 let key = u128::from(this.read_scalar(key)?.to_u32()?);
676 let active_thread = this.active_thread();
677 let new_data = this.read_scalar(new_ptr)?;
678 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
679
680 this.write_int(1, dest)?;
682 }
683 "TlsFree" => {
684 let [key] = this.check_shim_sig(
686 shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
687 link_name,
688 abi,
689 args,
690 )?;
691 let key = u128::from(this.read_scalar(key)?.to_u32()?);
692 this.machine.tls.delete_tls_key(key)?;
693
694 this.write_int(1, dest)?;
696 }
697
698 "FlsAlloc" => {
700 let [dtor] = this.check_shim_sig(
703 shim_sig!(extern "system" fn(winapi::PFLS_CALLBACK_FUNCTION) -> u32),
704 link_name,
705 abi,
706 args,
707 )?;
708 let dtor = this.read_pointer(dtor)?;
709
710 let dtor = if !this.ptr_is_null(dtor)? {
712 Some((
713 this.get_ptr_fn(dtor)?.as_instance()?,
714 this.machine.current_user_relevant_span(),
715 ))
716 } else {
717 None
718 };
719
720 let key = this.machine.tls.create_tls_key(dtor, dest.layout.size)?;
721 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
722 }
723 "FlsGetValue" => {
724 let [key] = this.check_shim_sig(
726 shim_sig!(extern "system" fn(u32) -> *mut _),
727 link_name,
728 abi,
729 args,
730 )?;
731 let key = u128::from(this.read_scalar(key)?.to_u32()?);
732 let active_thread = this.active_thread();
733 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
734 this.write_scalar(ptr, dest)?;
735 }
736 "FlsSetValue" => {
737 let [key, new_ptr] = this.check_shim_sig(
739 shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL),
740 link_name,
741 abi,
742 args,
743 )?;
744 let key = u128::from(this.read_scalar(key)?.to_u32()?);
745 let active_thread = this.active_thread();
746 let new_data = this.read_scalar(new_ptr)?;
747 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
748
749 this.write_int(1, dest)?;
751 }
752 "FlsFree" => {
753 let [key] = this.check_shim_sig(
755 shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
756 link_name,
757 abi,
758 args,
759 )?;
760 let key = u128::from(this.read_scalar(key)?.to_u32()?);
761 let tls_entry = this.machine.tls.delete_tls_key(key)?;
762
763 if !tls_entry.data.is_empty() && tls_entry.dtor.is_some() {
765 throw_unsup_format!(
766 "calling `FlsFree` on a key with an associated dtor is not supported"
767 );
768 }
769
770 this.write_int(1, dest)?;
772 }
773 "IsThreadAFiber" => {
774 let [] = this.check_shim_sig(
776 shim_sig!(extern "system" fn() -> winapi::BOOL),
777 link_name,
778 abi,
779 args,
780 )?;
781
782 this.write_int(0, dest)?;
784 }
785
786 "GetCommandLineW" => {
788 let [] = this.check_shim_sig(
790 shim_sig!(extern "system" fn() -> *mut _),
791 link_name,
792 abi,
793 args,
794 )?;
795 this.write_pointer(
796 this.machine.cmd_line.expect("machine must be initialized"),
797 dest,
798 )?;
799 }
800
801 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
803 let [filetime] = this.check_shim_sig(
805 shim_sig!(extern "system" fn(*mut _) -> ()),
806 link_name,
807 abi,
808 args,
809 )?;
810 this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?;
811 }
812 "QueryPerformanceCounter" => {
813 let [performance_count] = this.check_shim_sig(
815 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
816 link_name,
817 abi,
818 args,
819 )?;
820 let result = this.QueryPerformanceCounter(performance_count)?;
821 this.write_scalar(result, dest)?;
822 }
823 "QueryPerformanceFrequency" => {
824 let [frequency] = this.check_shim_sig(
826 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
827 link_name,
828 abi,
829 args,
830 )?;
831 let result = this.QueryPerformanceFrequency(frequency)?;
832 this.write_scalar(result, dest)?;
833 }
834 "Sleep" => {
835 let [timeout] = this.check_shim_sig(
837 shim_sig!(extern "system" fn(u32) -> ()),
838 link_name,
839 abi,
840 args,
841 )?;
842
843 this.Sleep(timeout)?;
844 }
845 "CreateWaitableTimerExW" => {
846 let [attributes, name, flags, access] = this.check_shim_sig(
848 shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE),
849 link_name,
850 abi,
851 args,
852 )?;
853 this.read_pointer(attributes)?;
854 this.read_pointer(name)?;
855 this.read_scalar(flags)?.to_u32()?;
856 this.read_scalar(access)?.to_u32()?;
857 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
859 this.set_last_error(not_supported)?;
860 this.write_null(dest)?;
861 }
862
863 "InitOnceBeginInitialize" => {
865 let [ptr, flags, pending, context] = this.check_shim_sig(
866 shim_sig!(extern "system" fn(*mut _, u32, *mut _, *mut _) -> winapi::BOOL),
867 link_name,
868 abi,
869 args,
870 )?;
871 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
872 }
873 "InitOnceComplete" => {
874 let [ptr, flags, context] = this.check_shim_sig(
875 shim_sig!(extern "system" fn(*mut _, u32, *mut _) -> winapi::BOOL),
876 link_name,
877 abi,
878 args,
879 )?;
880 let result = this.InitOnceComplete(ptr, flags, context)?;
881 this.write_scalar(result, dest)?;
882 }
883 "WaitOnAddress" => {
884 let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig(
886 shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL),
888 link_name,
889 abi,
890 args,
891 )?;
892
893 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
894 }
895 "WakeByAddressSingle" => {
896 let [ptr_op] = this.check_shim_sig(
898 shim_sig!(extern "system" fn(*mut _) -> ()),
899 link_name,
900 abi,
901 args,
902 )?;
903
904 this.WakeByAddressSingle(ptr_op)?;
905 }
906 "WakeByAddressAll" => {
907 let [ptr_op] = this.check_shim_sig(
909 shim_sig!(extern "system" fn(*mut _) -> ()),
910 link_name,
911 abi,
912 args,
913 )?;
914
915 this.WakeByAddressAll(ptr_op)?;
916 }
917
918 "GetProcAddress" => {
920 let [module, proc_name] = this.check_shim_sig(
922 shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC),
923 link_name,
924 abi,
925 args,
926 )?;
927 this.read_target_isize(module)?;
928 let name = this.read_c_str(this.read_pointer(proc_name)?)?;
929 if let Ok(name) = str::from_utf8(name)
930 && is_dyn_sym(name)
931 {
932 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
933 this.write_pointer(ptr, dest)?;
934 } else {
935 this.write_null(dest)?;
936 }
937 }
938
939 "CreateThread" => {
941 let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig(
942 shim_sig!(
943 extern "system" fn(
944 *mut _,
945 usize,
946 *mut _,
947 *mut _,
948 u32,
949 *mut _,
950 ) -> winapi::HANDLE
951 ),
952 link_name,
953 abi,
954 args,
955 )?;
956
957 let thread_id =
958 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
959
960 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
961 }
962 "WaitForSingleObject" => {
963 let [handle, timeout] = this.check_shim_sig(
964 shim_sig!(extern "system" fn(winapi::HANDLE, u32) -> u32),
965 link_name,
966 abi,
967 args,
968 )?;
969
970 this.WaitForSingleObject(handle, timeout, dest)?;
971 }
972 "GetCurrentProcess" => {
973 let [] = this.check_shim_sig(
974 shim_sig!(extern "system" fn() -> winapi::HANDLE),
975 link_name,
976 abi,
977 args,
978 )?;
979
980 this.write_scalar(
981 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
982 dest,
983 )?;
984 }
985 "GetCurrentThread" => {
986 let [] = this.check_shim_sig(
987 shim_sig!(extern "system" fn() -> winapi::HANDLE),
988 link_name,
989 abi,
990 args,
991 )?;
992
993 this.write_scalar(
994 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
995 dest,
996 )?;
997 }
998 "SetThreadDescription" => {
999 let [handle, name] = this.check_shim_sig(
1000 shim_sig!(extern "system" fn(winapi::HANDLE, *const _) -> i32),
1001 link_name,
1002 abi,
1003 args,
1004 )?;
1005
1006 let handle = this.read_handle(handle, "SetThreadDescription")?;
1007 let name = this.read_wide_str(this.read_pointer(name)?)?;
1008
1009 let thread = match handle {
1010 Handle::Thread(thread) => thread,
1011 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
1012 _ => this.invalid_handle("SetThreadDescription")?,
1013 };
1014 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
1016 this.write_scalar(Scalar::from_u32(0), dest)?;
1017 }
1018 "GetThreadDescription" => {
1019 let [handle, name_ptr] = this.check_shim_sig(
1020 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> i32),
1021 link_name,
1022 abi,
1023 args,
1024 )?;
1025
1026 let handle = this.read_handle(handle, "GetThreadDescription")?;
1027 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
1030 Handle::Thread(thread) => thread,
1031 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
1032 _ => this.invalid_handle("GetThreadDescription")?,
1033 };
1034 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
1036 let name = this.alloc_os_str_as_wide_str(
1037 bytes_to_os_str(&name)?,
1038 MiriMemoryKind::WinLocal.into(),
1039 )?;
1040 let name = Scalar::from_maybe_pointer(name, this);
1041 let res = Scalar::from_u32(0);
1042
1043 this.write_scalar(name, &name_ptr)?;
1044 this.write_scalar(res, dest)?;
1045 }
1046 "GetThreadId" => {
1047 let [handle] = this.check_shim_sig(
1048 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
1049 link_name,
1050 abi,
1051 args,
1052 )?;
1053 let handle = this.read_handle(handle, "GetThreadId")?;
1054 let thread = match handle {
1055 Handle::Thread(thread) => thread,
1056 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
1057 _ => this.invalid_handle("GetThreadDescription")?,
1058 };
1059 this.write_scalar(Scalar::from_u32(thread.to_u32()), dest)?;
1060 }
1061 "GetCurrentThreadId" => {
1062 let [] = this.check_shim_sig(
1063 shim_sig!(extern "system" fn() -> u32),
1064 link_name,
1065 abi,
1066 args,
1067 )?;
1068 this.write_scalar(Scalar::from_u32(this.active_thread().to_u32()), dest)?;
1069 }
1070
1071 "ExitProcess" => {
1073 let [code] = this.check_shim_sig(
1075 shim_sig!(extern "system" fn(u32) -> ()),
1076 link_name,
1077 abi,
1078 args,
1079 )?;
1080 let code = this.read_scalar(code)?.to_i32()?;
1082 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
1083 }
1084 "SystemFunction036" => {
1085 let [ptr, len] = this.check_shim_sig(
1088 shim_sig!(extern "system" fn(*mut _, u32) -> u8),
1090 link_name,
1091 abi,
1092 args,
1093 )?;
1094 let ptr = this.read_pointer(ptr)?;
1095 let len = this.read_scalar(len)?.to_u32()?;
1096 this.gen_random(ptr, len.into())?;
1097 this.write_scalar(Scalar::from_bool(true), dest)?;
1098 }
1099 "ProcessPrng" => {
1100 let [ptr, len] = this.check_shim_sig(
1103 shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL),
1104 link_name,
1105 abi,
1106 args,
1107 )?;
1108 let ptr = this.read_pointer(ptr)?;
1109 let len = this.read_target_usize(len)?;
1110 this.gen_random(ptr, len)?;
1111 this.write_int(1, dest)?;
1112 }
1113 "BCryptGenRandom" => {
1114 let [algorithm, ptr, len, flags] = this.check_shim_sig(
1116 shim_sig!(extern "system" fn(*mut _, *mut _, u32, u32) -> i32),
1117 link_name,
1118 abi,
1119 args,
1120 )?;
1121 let algorithm = this.read_scalar(algorithm)?;
1122 let algorithm = algorithm.to_target_usize(this)?;
1123 let ptr = this.read_pointer(ptr)?;
1124 let len = this.read_scalar(len)?.to_u32()?;
1125 let flags = this.read_scalar(flags)?.to_u32()?;
1126 match flags {
1127 0 => {
1128 if algorithm != 0x81 {
1129 throw_unsup_format!(
1131 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
1132 );
1133 }
1134 }
1135 2 => {
1136 if algorithm != 0 {
1138 throw_unsup_format!(
1139 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
1140 );
1141 }
1142 }
1143 _ => {
1144 throw_unsup_format!(
1145 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
1146 );
1147 }
1148 }
1149 this.gen_random(ptr, len.into())?;
1150 this.write_null(dest)?; }
1152 "GetConsoleScreenBufferInfo" => {
1153 let [console, buffer_info] = this.check_shim_sig(
1156 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1157 link_name,
1158 abi,
1159 args,
1160 )?;
1161 this.read_target_isize(console)?;
1162 this.deref_pointer(buffer_info)?;
1164 this.write_null(dest)?;
1167 }
1168 "GetStdHandle" => {
1169 let [which] = this.check_shim_sig(
1171 shim_sig!(extern "system" fn(u32) -> winapi::HANDLE),
1172 link_name,
1173 abi,
1174 args,
1175 )?;
1176 let res = this.GetStdHandle(which)?;
1177 this.write_scalar(res, dest)?;
1178 }
1179 "DuplicateHandle" => {
1180 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
1181 this.check_shim_sig(
1182 shim_sig!(
1183 extern "system" fn(
1184 winapi::HANDLE,
1185 winapi::HANDLE,
1186 winapi::HANDLE,
1187 *mut _,
1188 u32,
1189 winapi::BOOL,
1190 u32,
1191 ) -> winapi::BOOL
1192 ),
1193 link_name,
1194 abi,
1195 args,
1196 )?;
1197 let res = this.DuplicateHandle(
1198 src_proc,
1199 src_handle,
1200 target_proc,
1201 target_handle,
1202 access,
1203 inherit,
1204 options,
1205 )?;
1206 this.write_scalar(res, dest)?;
1207 }
1208 "CloseHandle" => {
1209 let [handle] = this.check_shim_sig(
1210 shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
1211 link_name,
1212 abi,
1213 args,
1214 )?;
1215
1216 let ret = this.CloseHandle(handle)?;
1217
1218 this.write_scalar(ret, dest)?;
1219 }
1220 "GetModuleFileNameW" => {
1221 let [handle, filename, size] = this.check_shim_sig(
1223 shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32),
1224 link_name,
1225 abi,
1226 args,
1227 )?;
1228 this.check_no_isolation("`GetModuleFileNameW`")?;
1229
1230 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
1231 let filename = this.read_pointer(filename)?;
1232 let size = this.read_scalar(size)?.to_u32()?;
1233
1234 if handle != Handle::Null {
1235 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
1236 }
1237
1238 let path = std::env::current_exe().unwrap();
1241 let (all_written, size_needed) =
1242 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
1243
1244 if all_written {
1245 this.write_int(size_needed.strict_sub(1), dest)?;
1249 } else {
1250 this.write_int(size, dest)?;
1255 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
1256 this.set_last_error(insufficient_buffer)?;
1257 }
1258 }
1259 "FormatMessageW" => {
1260 let [flags, module, message_id, language_id, buffer, size, arguments] = this
1262 .check_shim_sig(
1263 shim_sig!(
1264 extern "system" fn(u32, *const _, u32, u32, *mut _, u32, *mut _) -> u32
1265 ),
1266 link_name,
1267 abi,
1268 args,
1269 )?;
1270
1271 let flags = this.read_scalar(flags)?.to_u32()?;
1272 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
1274 let _language_id = this.read_scalar(language_id)?.to_u32()?;
1275 let buffer = this.read_pointer(buffer)?;
1276 let size = this.read_scalar(size)?.to_u32()?;
1277 let _arguments = this.read_pointer(arguments)?;
1278
1279 if flags != 4096u32 | 512u32 {
1282 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
1283 }
1284
1285 let error = this.try_errnum_to_io_error(message_id)?;
1286 let formatted = match error {
1287 Some(err) => format!("{err}"),
1288 None => format!("<unknown error in FormatMessageW: {message_id}>"),
1289 };
1290 let (complete, length) =
1291 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
1292 if !complete {
1293 throw_unsup_format!("FormatMessageW: buffer not big enough");
1296 }
1297 this.write_int(length.strict_sub(1), dest)?;
1299 }
1300
1301 "_Unwind_RaiseException" => {
1302 if this.tcx.sess.target.env != Env::Gnu {
1308 throw_unsup_format!(
1309 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
1310 );
1311 }
1312 let [payload] = this.check_shim_sig(
1314 shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code),
1315 link_name,
1316 abi,
1317 args,
1318 )?;
1319 this.handle_miri_start_unwind(payload)?;
1320 return interp_ok(EmulateItemResult::NeedsUnwind);
1321 }
1322
1323 "GetProcessHeap" if this.frame_in_std() => {
1326 let [] = this.check_shim_sig(
1327 shim_sig!(extern "system" fn() -> winapi::HANDLE),
1328 link_name,
1329 abi,
1330 args,
1331 )?;
1332 this.write_int(1, dest)?;
1335 }
1336 "GetModuleHandleA" if this.frame_in_std() => {
1337 let [_module_name] = this.check_shim_sig(
1338 shim_sig!(extern "system" fn(*const _) -> winapi::HMODULE),
1339 link_name,
1340 abi,
1341 args,
1342 )?;
1343 this.write_int(1, dest)?;
1345 }
1346 "SetConsoleTextAttribute" if this.frame_in_std() => {
1347 let [_console_output, _attribute] = this.check_shim_sig(
1348 shim_sig!(extern "system" fn(winapi::HANDLE, u16) -> winapi::BOOL),
1349 link_name,
1350 abi,
1351 args,
1352 )?;
1353 this.write_null(dest)?;
1355 }
1356 "GetConsoleMode" if this.frame_in_std() => {
1357 let [console, mode] = this.check_shim_sig(
1358 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1359 link_name,
1360 abi,
1361 args,
1362 )?;
1363 this.read_target_isize(console)?;
1364 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
1365 this.write_null(dest)?;
1367 }
1368 "GetFileType" if this.frame_in_std() => {
1369 let [_file] = this.check_shim_sig(
1370 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
1371 link_name,
1372 abi,
1373 args,
1374 )?;
1375 this.write_null(dest)?;
1377 }
1378 "AddVectoredExceptionHandler" if this.frame_in_std() => {
1379 let [_first, _handler] = this.check_shim_sig(
1380 shim_sig!(extern "system" fn(u32, *mut _) -> *mut _),
1381 link_name,
1382 abi,
1383 args,
1384 )?;
1385 this.write_int(1, dest)?;
1387 }
1388 "SetThreadStackGuarantee" if this.frame_in_std() => {
1389 let [_stack_size_in_bytes] = this.check_shim_sig(
1390 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
1391 link_name,
1392 abi,
1393 args,
1394 )?;
1395 this.write_int(1, dest)?;
1397 }
1398 "SwitchToThread" if this.frame_in_std() => {
1400 let [] = this.check_shim_sig(
1401 shim_sig!(extern "system" fn() -> winapi::BOOL),
1402 link_name,
1403 abi,
1404 args,
1405 )?;
1406
1407 this.yield_active_thread();
1408
1409 this.write_null(dest)?;
1411 }
1412
1413 _ => return interp_ok(EmulateItemResult::NotSupported),
1414 }
1415
1416 interp_ok(EmulateItemResult::NeedsReturn)
1417 }
1418}