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(
645 shim_sig!(extern "system" fn() -> u32),
646 link_name,
647 abi,
648 args,
649 )?;
650 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
651 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
652 }
653 "TlsGetValue" => {
654 let [key] = this.check_shim_sig(
655 shim_sig!(extern "system" fn(u32) -> *mut _),
656 link_name,
657 abi,
658 args,
659 )?;
660 let key = u128::from(this.read_scalar(key)?.to_u32()?);
661 let active_thread = this.active_thread();
662 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
663 this.write_scalar(ptr, dest)?;
664 }
665 "TlsSetValue" => {
666 let [key, new_ptr] = this.check_shim_sig(
667 shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL),
668 link_name,
669 abi,
670 args,
671 )?;
672 let key = u128::from(this.read_scalar(key)?.to_u32()?);
673 let active_thread = this.active_thread();
674 let new_data = this.read_scalar(new_ptr)?;
675 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
676
677 this.write_int(1, dest)?;
679 }
680 "TlsFree" => {
681 let [key] = this.check_shim_sig(
682 shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
683 link_name,
684 abi,
685 args,
686 )?;
687 let key = u128::from(this.read_scalar(key)?.to_u32()?);
688 this.machine.tls.delete_tls_key(key)?;
689
690 this.write_int(1, dest)?;
692 }
693
694 "GetCommandLineW" => {
696 let [] = this.check_shim_sig(
698 shim_sig!(extern "system" fn() -> *mut _),
699 link_name,
700 abi,
701 args,
702 )?;
703 this.write_pointer(
704 this.machine.cmd_line.expect("machine must be initialized"),
705 dest,
706 )?;
707 }
708
709 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
711 let [filetime] = this.check_shim_sig(
713 shim_sig!(extern "system" fn(*mut _) -> ()),
714 link_name,
715 abi,
716 args,
717 )?;
718 this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?;
719 }
720 "QueryPerformanceCounter" => {
721 let [performance_count] = 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.QueryPerformanceCounter(performance_count)?;
729 this.write_scalar(result, dest)?;
730 }
731 "QueryPerformanceFrequency" => {
732 let [frequency] = this.check_shim_sig(
734 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
735 link_name,
736 abi,
737 args,
738 )?;
739 let result = this.QueryPerformanceFrequency(frequency)?;
740 this.write_scalar(result, dest)?;
741 }
742 "Sleep" => {
743 let [timeout] = this.check_shim_sig(
745 shim_sig!(extern "system" fn(u32) -> ()),
746 link_name,
747 abi,
748 args,
749 )?;
750
751 this.Sleep(timeout)?;
752 }
753 "CreateWaitableTimerExW" => {
754 let [attributes, name, flags, access] = this.check_shim_sig(
756 shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE),
757 link_name,
758 abi,
759 args,
760 )?;
761 this.read_pointer(attributes)?;
762 this.read_pointer(name)?;
763 this.read_scalar(flags)?.to_u32()?;
764 this.read_scalar(access)?.to_u32()?;
765 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
767 this.set_last_error(not_supported)?;
768 this.write_null(dest)?;
769 }
770
771 "InitOnceBeginInitialize" => {
773 let [ptr, flags, pending, context] = this.check_shim_sig(
774 shim_sig!(extern "system" fn(*mut _, u32, *mut _, *mut _) -> winapi::BOOL),
775 link_name,
776 abi,
777 args,
778 )?;
779 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
780 }
781 "InitOnceComplete" => {
782 let [ptr, flags, context] = this.check_shim_sig(
783 shim_sig!(extern "system" fn(*mut _, u32, *mut _) -> winapi::BOOL),
784 link_name,
785 abi,
786 args,
787 )?;
788 let result = this.InitOnceComplete(ptr, flags, context)?;
789 this.write_scalar(result, dest)?;
790 }
791 "WaitOnAddress" => {
792 let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig(
794 shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL),
796 link_name,
797 abi,
798 args,
799 )?;
800
801 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
802 }
803 "WakeByAddressSingle" => {
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.WakeByAddressSingle(ptr_op)?;
813 }
814 "WakeByAddressAll" => {
815 let [ptr_op] = this.check_shim_sig(
817 shim_sig!(extern "system" fn(*mut _) -> ()),
818 link_name,
819 abi,
820 args,
821 )?;
822
823 this.WakeByAddressAll(ptr_op)?;
824 }
825
826 "GetProcAddress" => {
828 let [module, proc_name] = this.check_shim_sig(
830 shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC),
831 link_name,
832 abi,
833 args,
834 )?;
835 this.read_target_isize(module)?;
836 let name = this.read_c_str(this.read_pointer(proc_name)?)?;
837 if let Ok(name) = str::from_utf8(name)
838 && is_dyn_sym(name)
839 {
840 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
841 this.write_pointer(ptr, dest)?;
842 } else {
843 this.write_null(dest)?;
844 }
845 }
846
847 "CreateThread" => {
849 let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig(
850 shim_sig!(
851 extern "system" fn(
852 *mut _,
853 usize,
854 *mut _,
855 *mut _,
856 u32,
857 *mut _,
858 ) -> winapi::HANDLE
859 ),
860 link_name,
861 abi,
862 args,
863 )?;
864
865 let thread_id =
866 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
867
868 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
869 }
870 "WaitForSingleObject" => {
871 let [handle, timeout] = this.check_shim_sig(
872 shim_sig!(extern "system" fn(winapi::HANDLE, u32) -> u32),
873 link_name,
874 abi,
875 args,
876 )?;
877
878 this.WaitForSingleObject(handle, timeout, dest)?;
879 }
880 "GetCurrentProcess" => {
881 let [] = this.check_shim_sig(
882 shim_sig!(extern "system" fn() -> winapi::HANDLE),
883 link_name,
884 abi,
885 args,
886 )?;
887
888 this.write_scalar(
889 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
890 dest,
891 )?;
892 }
893 "GetCurrentThread" => {
894 let [] = this.check_shim_sig(
895 shim_sig!(extern "system" fn() -> winapi::HANDLE),
896 link_name,
897 abi,
898 args,
899 )?;
900
901 this.write_scalar(
902 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
903 dest,
904 )?;
905 }
906 "SetThreadDescription" => {
907 let [handle, name] = this.check_shim_sig(
908 shim_sig!(extern "system" fn(winapi::HANDLE, *const _) -> i32),
909 link_name,
910 abi,
911 args,
912 )?;
913
914 let handle = this.read_handle(handle, "SetThreadDescription")?;
915 let name = this.read_wide_str(this.read_pointer(name)?)?;
916
917 let thread = match handle {
918 Handle::Thread(thread) => thread,
919 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
920 _ => this.invalid_handle("SetThreadDescription")?,
921 };
922 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
924 this.write_scalar(Scalar::from_u32(0), dest)?;
925 }
926 "GetThreadDescription" => {
927 let [handle, name_ptr] = this.check_shim_sig(
928 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> i32),
929 link_name,
930 abi,
931 args,
932 )?;
933
934 let handle = this.read_handle(handle, "GetThreadDescription")?;
935 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
938 Handle::Thread(thread) => thread,
939 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
940 _ => this.invalid_handle("GetThreadDescription")?,
941 };
942 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
944 let name = this.alloc_os_str_as_wide_str(
945 bytes_to_os_str(&name)?,
946 MiriMemoryKind::WinLocal.into(),
947 )?;
948 let name = Scalar::from_maybe_pointer(name, this);
949 let res = Scalar::from_u32(0);
950
951 this.write_scalar(name, &name_ptr)?;
952 this.write_scalar(res, dest)?;
953 }
954 "GetThreadId" => {
955 let [handle] = this.check_shim_sig(
956 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
957 link_name,
958 abi,
959 args,
960 )?;
961 let handle = this.read_handle(handle, "GetThreadId")?;
962 let thread = match handle {
963 Handle::Thread(thread) => thread,
964 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
965 _ => this.invalid_handle("GetThreadDescription")?,
966 };
967 this.write_scalar(Scalar::from_u32(thread.to_u32()), dest)?;
968 }
969 "GetCurrentThreadId" => {
970 let [] = this.check_shim_sig(
971 shim_sig!(extern "system" fn() -> u32),
972 link_name,
973 abi,
974 args,
975 )?;
976 this.write_scalar(Scalar::from_u32(this.active_thread().to_u32()), dest)?;
977 }
978
979 "ExitProcess" => {
981 let [code] = this.check_shim_sig(
983 shim_sig!(extern "system" fn(u32) -> ()),
984 link_name,
985 abi,
986 args,
987 )?;
988 let code = this.read_scalar(code)?.to_i32()?;
990 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
991 }
992 "SystemFunction036" => {
993 let [ptr, len] = this.check_shim_sig(
996 shim_sig!(extern "system" fn(*mut _, u32) -> u8),
998 link_name,
999 abi,
1000 args,
1001 )?;
1002 let ptr = this.read_pointer(ptr)?;
1003 let len = this.read_scalar(len)?.to_u32()?;
1004 this.gen_random(ptr, len.into())?;
1005 this.write_scalar(Scalar::from_bool(true), dest)?;
1006 }
1007 "ProcessPrng" => {
1008 let [ptr, len] = this.check_shim_sig(
1011 shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL),
1012 link_name,
1013 abi,
1014 args,
1015 )?;
1016 let ptr = this.read_pointer(ptr)?;
1017 let len = this.read_target_usize(len)?;
1018 this.gen_random(ptr, len)?;
1019 this.write_int(1, dest)?;
1020 }
1021 "BCryptGenRandom" => {
1022 let [algorithm, ptr, len, flags] = this.check_shim_sig(
1024 shim_sig!(extern "system" fn(*mut _, *mut _, u32, u32) -> i32),
1025 link_name,
1026 abi,
1027 args,
1028 )?;
1029 let algorithm = this.read_scalar(algorithm)?;
1030 let algorithm = algorithm.to_target_usize(this)?;
1031 let ptr = this.read_pointer(ptr)?;
1032 let len = this.read_scalar(len)?.to_u32()?;
1033 let flags = this.read_scalar(flags)?.to_u32()?;
1034 match flags {
1035 0 => {
1036 if algorithm != 0x81 {
1037 throw_unsup_format!(
1039 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
1040 );
1041 }
1042 }
1043 2 => {
1044 if algorithm != 0 {
1046 throw_unsup_format!(
1047 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
1048 );
1049 }
1050 }
1051 _ => {
1052 throw_unsup_format!(
1053 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
1054 );
1055 }
1056 }
1057 this.gen_random(ptr, len.into())?;
1058 this.write_null(dest)?; }
1060 "GetConsoleScreenBufferInfo" => {
1061 let [console, buffer_info] = this.check_shim_sig(
1064 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1065 link_name,
1066 abi,
1067 args,
1068 )?;
1069 this.read_target_isize(console)?;
1070 this.deref_pointer(buffer_info)?;
1072 this.write_null(dest)?;
1075 }
1076 "GetStdHandle" => {
1077 let [which] = this.check_shim_sig(
1079 shim_sig!(extern "system" fn(u32) -> winapi::HANDLE),
1080 link_name,
1081 abi,
1082 args,
1083 )?;
1084 let res = this.GetStdHandle(which)?;
1085 this.write_scalar(res, dest)?;
1086 }
1087 "DuplicateHandle" => {
1088 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
1089 this.check_shim_sig(
1090 shim_sig!(
1091 extern "system" fn(
1092 winapi::HANDLE,
1093 winapi::HANDLE,
1094 winapi::HANDLE,
1095 *mut _,
1096 u32,
1097 winapi::BOOL,
1098 u32,
1099 ) -> winapi::BOOL
1100 ),
1101 link_name,
1102 abi,
1103 args,
1104 )?;
1105 let res = this.DuplicateHandle(
1106 src_proc,
1107 src_handle,
1108 target_proc,
1109 target_handle,
1110 access,
1111 inherit,
1112 options,
1113 )?;
1114 this.write_scalar(res, dest)?;
1115 }
1116 "CloseHandle" => {
1117 let [handle] = this.check_shim_sig(
1118 shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
1119 link_name,
1120 abi,
1121 args,
1122 )?;
1123
1124 let ret = this.CloseHandle(handle)?;
1125
1126 this.write_scalar(ret, dest)?;
1127 }
1128 "GetModuleFileNameW" => {
1129 let [handle, filename, size] = this.check_shim_sig(
1131 shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32),
1132 link_name,
1133 abi,
1134 args,
1135 )?;
1136 this.check_no_isolation("`GetModuleFileNameW`")?;
1137
1138 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
1139 let filename = this.read_pointer(filename)?;
1140 let size = this.read_scalar(size)?.to_u32()?;
1141
1142 if handle != Handle::Null {
1143 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
1144 }
1145
1146 let path = std::env::current_exe().unwrap();
1149 let (all_written, size_needed) =
1150 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
1151
1152 if all_written {
1153 this.write_int(size_needed.strict_sub(1), dest)?;
1157 } else {
1158 this.write_int(size, dest)?;
1163 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
1164 this.set_last_error(insufficient_buffer)?;
1165 }
1166 }
1167 "FormatMessageW" => {
1168 let [flags, module, message_id, language_id, buffer, size, arguments] = this
1170 .check_shim_sig(
1171 shim_sig!(
1172 extern "system" fn(u32, *const _, u32, u32, *mut _, u32, *mut _) -> u32
1173 ),
1174 link_name,
1175 abi,
1176 args,
1177 )?;
1178
1179 let flags = this.read_scalar(flags)?.to_u32()?;
1180 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
1182 let _language_id = this.read_scalar(language_id)?.to_u32()?;
1183 let buffer = this.read_pointer(buffer)?;
1184 let size = this.read_scalar(size)?.to_u32()?;
1185 let _arguments = this.read_pointer(arguments)?;
1186
1187 if flags != 4096u32 | 512u32 {
1190 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
1191 }
1192
1193 let error = this.try_errnum_to_io_error(message_id)?;
1194 let formatted = match error {
1195 Some(err) => format!("{err}"),
1196 None => format!("<unknown error in FormatMessageW: {message_id}>"),
1197 };
1198 let (complete, length) =
1199 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
1200 if !complete {
1201 throw_unsup_format!("FormatMessageW: buffer not big enough");
1204 }
1205 this.write_int(length.strict_sub(1), dest)?;
1207 }
1208
1209 "_Unwind_RaiseException" => {
1210 if this.tcx.sess.target.env != Env::Gnu {
1216 throw_unsup_format!(
1217 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
1218 );
1219 }
1220 let [payload] = this.check_shim_sig(
1222 shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code),
1223 link_name,
1224 abi,
1225 args,
1226 )?;
1227 this.handle_miri_start_unwind(payload)?;
1228 return interp_ok(EmulateItemResult::NeedsUnwind);
1229 }
1230
1231 "GetProcessHeap" if this.frame_in_std() => {
1234 let [] = this.check_shim_sig(
1235 shim_sig!(extern "system" fn() -> winapi::HANDLE),
1236 link_name,
1237 abi,
1238 args,
1239 )?;
1240 this.write_int(1, dest)?;
1243 }
1244 "GetModuleHandleA" if this.frame_in_std() => {
1245 let [_module_name] = this.check_shim_sig(
1246 shim_sig!(extern "system" fn(*const _) -> winapi::HMODULE),
1247 link_name,
1248 abi,
1249 args,
1250 )?;
1251 this.write_int(1, dest)?;
1253 }
1254 "SetConsoleTextAttribute" if this.frame_in_std() => {
1255 let [_console_output, _attribute] = this.check_shim_sig(
1256 shim_sig!(extern "system" fn(winapi::HANDLE, u16) -> winapi::BOOL),
1257 link_name,
1258 abi,
1259 args,
1260 )?;
1261 this.write_null(dest)?;
1263 }
1264 "GetConsoleMode" if this.frame_in_std() => {
1265 let [console, mode] = this.check_shim_sig(
1266 shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
1267 link_name,
1268 abi,
1269 args,
1270 )?;
1271 this.read_target_isize(console)?;
1272 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
1273 this.write_null(dest)?;
1275 }
1276 "GetFileType" if this.frame_in_std() => {
1277 let [_file] = this.check_shim_sig(
1278 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
1279 link_name,
1280 abi,
1281 args,
1282 )?;
1283 this.write_null(dest)?;
1285 }
1286 "AddVectoredExceptionHandler" if this.frame_in_std() => {
1287 let [_first, _handler] = this.check_shim_sig(
1288 shim_sig!(extern "system" fn(u32, *mut _) -> *mut _),
1289 link_name,
1290 abi,
1291 args,
1292 )?;
1293 this.write_int(1, dest)?;
1295 }
1296 "SetThreadStackGuarantee" if this.frame_in_std() => {
1297 let [_stack_size_in_bytes] = this.check_shim_sig(
1298 shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
1299 link_name,
1300 abi,
1301 args,
1302 )?;
1303 this.write_int(1, dest)?;
1305 }
1306 "SwitchToThread" if this.frame_in_std() => {
1308 let [] = this.check_shim_sig(
1309 shim_sig!(extern "system" fn() -> winapi::BOOL),
1310 link_name,
1311 abi,
1312 args,
1313 )?;
1314
1315 this.yield_active_thread();
1316
1317 this.write_null(dest)?;
1319 }
1320
1321 _ => return interp_ok(EmulateItemResult::NotSupported),
1322 }
1323
1324 interp_ok(EmulateItemResult::NeedsReturn)
1325 }
1326}