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(*_, *_, u32) -> u32),
154 (link_name, abi, args),
155 )?;
156 let result = this.GetEnvironmentVariableW(name, buf, size)?;
157 this.write_scalar(result, dest)?;
158 }
159 "SetEnvironmentVariableW" => {
160 let [name, value] = this.check_shim_sig(
162 shim_sig!(extern "system" fn(*_, *_) -> winapi::BOOL),
163 (link_name, abi, args),
164 )?;
165 let result = this.SetEnvironmentVariableW(name, value)?;
166 this.write_scalar(result, dest)?;
167 }
168 "GetEnvironmentStringsW" => {
169 let [] = this.check_shim_sig(
171 shim_sig!(extern "system" fn() -> *_),
172 (link_name, abi, args),
173 )?;
174 let result = this.GetEnvironmentStringsW()?;
175 this.write_pointer(result, dest)?;
176 }
177 "FreeEnvironmentStringsW" => {
178 let [env_block] = this.check_shim_sig(
180 shim_sig!(extern "system" fn(*_) -> winapi::BOOL),
181 (link_name, abi, args),
182 )?;
183 let result = this.FreeEnvironmentStringsW(env_block)?;
184 this.write_scalar(result, dest)?;
185 }
186 "GetCurrentDirectoryW" => {
187 let [size, buf] = this.check_shim_sig(
189 shim_sig!(extern "system" fn(u32, *_) -> u32),
190 (link_name, abi, args),
191 )?;
192 let result = this.GetCurrentDirectoryW(size, buf)?;
193 this.write_scalar(result, dest)?;
194 }
195 "SetCurrentDirectoryW" => {
196 let [path] = this.check_shim_sig(
198 shim_sig!(extern "system" fn(*_) -> winapi::BOOL),
199 (link_name, abi, args),
200 )?;
201 let result = this.SetCurrentDirectoryW(path)?;
202 this.write_scalar(result, dest)?;
203 }
204 "GetUserProfileDirectoryW" => {
205 let [token, buf, size] = this.check_shim_sig(
207 shim_sig!(extern "system" fn(winapi::HANDLE, *_, *_) -> winapi::BOOL),
208 (link_name, abi, args),
209 )?;
210 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
211 this.write_scalar(result, dest)?;
212 }
213 "GetCurrentProcessId" => {
214 let [] = this.check_shim_sig(
216 shim_sig!(extern "system" fn() -> u32),
217 (link_name, abi, args),
218 )?;
219 let result = this.GetCurrentProcessId()?;
220 this.write_scalar(result, dest)?;
221 }
222 "GetTempPathW" => {
223 let [bufferlength, buffer] = this.check_shim_sig(
225 shim_sig!(extern "system" fn(u32, *_) -> u32),
226 (link_name, abi, args),
227 )?;
228 let result = this.GetTempPathW(bufferlength, buffer)?;
229 this.write_scalar(result, dest)?;
230 }
231
232 "NtWriteFile" => {
234 let [
235 handle,
236 event,
237 apc_routine,
238 apc_context,
239 io_status_block,
240 buf,
241 n,
242 byte_offset,
243 key,
244 ] = this.check_shim_sig(
245 shim_sig!(
246 extern "system" fn(
247 winapi::HANDLE,
248 winapi::HANDLE,
249 *_,
250 *_,
251 *_,
252 *_,
253 u32,
254 *_,
255 *_,
256 ) -> i32
257 ),
258 (link_name, abi, args),
259 )?;
260 this.NtWriteFile(
261 handle,
262 event,
263 apc_routine,
264 apc_context,
265 io_status_block,
266 buf,
267 n,
268 byte_offset,
269 key,
270 dest,
271 )?;
272 }
273 "NtReadFile" => {
274 let [
275 handle,
276 event,
277 apc_routine,
278 apc_context,
279 io_status_block,
280 buf,
281 n,
282 byte_offset,
283 key,
284 ] = this.check_shim_sig(
285 shim_sig!(
286 extern "system" fn(
287 winapi::HANDLE,
288 winapi::HANDLE,
289 *_,
290 *_,
291 *_,
292 *_,
293 u32,
294 *_,
295 *_,
296 ) -> i32
297 ),
298 (link_name, abi, args),
299 )?;
300 this.NtReadFile(
301 handle,
302 event,
303 apc_routine,
304 apc_context,
305 io_status_block,
306 buf,
307 n,
308 byte_offset,
309 key,
310 dest,
311 )?;
312 }
313 "GetFullPathNameW" => {
314 let [filename, size, buffer, filepart] = this.check_shim_sig(
316 shim_sig!(extern "system" fn(*_, u32, *_, *_) -> u32),
317 (link_name, abi, args),
318 )?;
319 this.check_no_isolation("`GetFullPathNameW`")?;
320
321 let filename = this.read_pointer(filename)?;
322 let size = this.read_scalar(size)?.to_u32()?;
323 let buffer = this.read_pointer(buffer)?;
324 let filepart = this.read_pointer(filepart)?;
325
326 if !this.ptr_is_null(filepart)? {
327 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
328 }
329
330 let filename = this.read_path_from_wide_str(filename)?;
331 let result = match win_get_full_path_name(&filename)? {
332 Err(err) => {
333 this.set_last_error(err)?;
334 Scalar::from_u32(0) }
336 Ok(abs_filename) => {
337 Scalar::from_u32(helpers::windows_check_buffer_size(
338 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
339 ))
340 }
343 };
344 this.write_scalar(result, dest)?;
345 }
346 "CreateFileW" => {
347 let [
348 file_name,
349 desired_access,
350 share_mode,
351 security_attributes,
352 creation_disposition,
353 flags_and_attributes,
354 template_file,
355 ] = this.check_shim_sig(
356 shim_sig!(
357 extern "system" fn(
358 *_,
359 u32,
360 u32,
361 *_,
362 u32,
363 u32,
364 winapi::HANDLE,
365 ) -> winapi::HANDLE
366 ),
367 (link_name, abi, args),
368 )?;
369 let handle = this.CreateFileW(
370 file_name,
371 desired_access,
372 share_mode,
373 security_attributes,
374 creation_disposition,
375 flags_and_attributes,
376 template_file,
377 )?;
378 this.write_scalar(handle.to_scalar(this), dest)?;
379 }
380 "GetFileInformationByHandle" => {
381 let [handle, info] = this.check_shim_sig(
382 shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> winapi::BOOL),
383 (link_name, abi, args),
384 )?;
385 let res = this.GetFileInformationByHandle(handle, info)?;
386 this.write_scalar(res, dest)?;
387 }
388 "SetFileInformationByHandle" => {
389 let [handle, class, info, size] = this.check_shim_sig(
390 shim_sig!(
391 extern "system" fn(
392 winapi::HANDLE,
393 winapi::FILE_INFO_BY_HANDLE_CLASS,
394 *_,
395 u32,
396 ) -> winapi::BOOL
397 ),
398 (link_name, abi, args),
399 )?;
400 let res = this.SetFileInformationByHandle(handle, class, info, size)?;
401 this.write_scalar(res, dest)?;
402 }
403 "FlushFileBuffers" => {
404 let [handle] = this.check_shim_sig(
405 shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
406 (link_name, abi, args),
407 )?;
408 let res = this.FlushFileBuffers(handle)?;
409 this.write_scalar(res, dest)?;
410 }
411 "DeleteFileW" => {
412 let [file_name] = this.check_shim_sig(
413 shim_sig!(extern "system" fn(*_) -> winapi::BOOL),
414 (link_name, abi, args),
415 )?;
416 let res = this.DeleteFileW(file_name)?;
417 this.write_scalar(res, dest)?;
418 }
419 "SetFilePointerEx" => {
420 let [file, distance_to_move, new_file_pointer, move_method] = this.check_shim_sig(
421 shim_sig!(extern "system" fn(winapi::HANDLE, i64, *_, u32) -> winapi::BOOL),
423 (link_name, abi, args),
424 )?;
425 let res =
426 this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
427 this.write_scalar(res, dest)?;
428 }
429 "MoveFileExW" => {
430 let [existing_name, new_name, flags] = this.check_shim_sig(
431 shim_sig!(extern "system" fn(*_, *_, u32) -> winapi::BOOL),
432 (link_name, abi, args),
433 )?;
434 let res = this.MoveFileExW(existing_name, new_name, flags)?;
435 this.write_scalar(res, dest)?;
436 }
437
438 "HeapAlloc" => {
440 let [handle, flags, size] = this.check_shim_sig(
442 shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *_),
443 (link_name, abi, args),
444 )?;
445 this.read_target_isize(handle)?;
446 let flags = this.read_scalar(flags)?.to_u32()?;
447 let size = this.read_target_usize(size)?;
448 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
449 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
450 AllocInit::Zero
451 } else {
452 AllocInit::Uninit
453 };
454 let align = this.tcx.pointer_size().bytes().strict_mul(2);
457 let ptr = this.allocate_ptr(
458 Size::from_bytes(size),
459 Align::from_bytes(align).unwrap(),
460 MiriMemoryKind::WinHeap.into(),
461 init,
462 )?;
463 this.write_pointer(ptr, dest)?;
464 }
465 "HeapFree" => {
466 let [handle, flags, ptr] = this.check_shim_sig(
468 shim_sig!(extern "system" fn(winapi::HANDLE, u32, *_) -> winapi::BOOL),
469 (link_name, abi, args),
470 )?;
471 this.read_target_isize(handle)?;
472 this.read_scalar(flags)?.to_u32()?;
473 let ptr = this.read_pointer(ptr)?;
474 if !this.ptr_is_null(ptr)? {
477 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
478 }
479 this.write_scalar(Scalar::from_i32(1), dest)?;
480 }
481 "HeapReAlloc" => {
482 let [handle, flags, old_ptr, size] = this.check_shim_sig(
484 shim_sig!(extern "system" fn(winapi::HANDLE, u32, *_, usize) -> *_),
485 (link_name, abi, args),
486 )?;
487 this.read_target_isize(handle)?;
488 this.read_scalar(flags)?.to_u32()?;
489 let old_ptr = this.read_pointer(old_ptr)?;
490 let size = this.read_target_usize(size)?;
491 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
496 old_ptr,
497 None,
498 Size::from_bytes(size),
499 Align::from_bytes(align).unwrap(),
500 MiriMemoryKind::WinHeap.into(),
501 AllocInit::Uninit,
502 )?;
503 this.write_pointer(new_ptr, dest)?;
504 }
505 "LocalFree" => {
506 let [ptr] = this.check_shim_sig(
508 shim_sig!(extern "system" fn(winapi::HLOCAL) -> winapi::HLOCAL),
509 (link_name, abi, args),
510 )?;
511 let ptr = this.read_pointer(ptr)?;
512 if !this.ptr_is_null(ptr)? {
515 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
516 }
517 this.write_null(dest)?;
518 }
519
520 "SetLastError" => {
522 let [error] = this.check_shim_sig(
523 shim_sig!(extern "system" fn(u32) -> ()),
524 (link_name, abi, args),
525 )?;
526 let error = this.read_scalar(error)?;
527 this.set_last_error(error)?;
528 }
529 "GetLastError" => {
530 let [] = this.check_shim_sig(
531 shim_sig!(extern "system" fn() -> u32),
532 (link_name, abi, args),
533 )?;
534 let last_error = this.get_last_error()?;
535 this.write_scalar(last_error, dest)?;
536 }
537 "RtlNtStatusToDosError" => {
538 let [status] = this.check_shim_sig(
539 shim_sig!(extern "system" fn(i32) -> u32),
540 (link_name, abi, args),
541 )?;
542 let status = this.read_scalar(status)?.to_u32()?;
543 let err = match status {
544 0xC00000A2 => 19,
546 0xC0000098 => 1006,
548 0xC000007F => 112,
550 0xC0000185 => 1117,
552 0xC0000022 => 5,
554 _ => 317,
556 };
557 this.write_scalar(Scalar::from_i32(err), dest)?;
558 }
559
560 "GetSystemInfo" => {
562 let [system_info] = this.check_shim_sig(
565 shim_sig!(extern "system" fn(*_) -> ()),
566 (link_name, abi, args),
567 )?;
568 let system_info =
569 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
570 this.write_bytes_ptr(
572 system_info.ptr(),
573 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
574 )?;
575 this.write_int_fields_named(
577 &[
578 ("dwPageSize", this.machine.page_size.into()),
579 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
580 ],
581 &system_info,
582 )?;
583 }
584
585 "TlsAlloc" => {
587 let [] = this.check_shim_sig(
592 shim_sig!(extern "system" fn() -> u32),
593 (link_name, abi, args),
594 )?;
595 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
596 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
597 }
598 "TlsGetValue" => {
599 let [key] = this.check_shim_sig(
601 shim_sig!(extern "system" fn(u32) -> *_),
602 (link_name, abi, args),
603 )?;
604 let key = u128::from(this.read_scalar(key)?.to_u32()?);
605 let active_thread = this.active_thread();
606 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
607 this.write_scalar(ptr, dest)?;
608 }
609 "TlsSetValue" => {
610 let [key, new_ptr] = this.check_shim_sig(
612 shim_sig!(extern "system" fn(u32, *_) -> winapi::BOOL),
613 (link_name, abi, args),
614 )?;
615 let key = u128::from(this.read_scalar(key)?.to_u32()?);
616 let active_thread = this.active_thread();
617 let new_data = this.read_scalar(new_ptr)?;
618 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
619
620 this.write_int(1, dest)?;
622 }
623 "TlsFree" => {
624 let [key] = this.check_shim_sig(
626 shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
627 (link_name, abi, args),
628 )?;
629 let key = u128::from(this.read_scalar(key)?.to_u32()?);
630 this.machine.tls.delete_tls_key(key)?;
631
632 this.write_int(1, dest)?;
634 }
635
636 "FlsAlloc" => {
638 let [dtor] = this.check_shim_sig(
641 shim_sig!(extern "system" fn(winapi::PFLS_CALLBACK_FUNCTION) -> u32),
642 (link_name, abi, args),
643 )?;
644 let dtor = this.read_pointer(dtor)?;
645
646 let dtor = if !this.ptr_is_null(dtor)? {
648 Some((
649 this.get_ptr_fn(dtor)?.as_instance()?,
650 this.machine.current_user_relevant_span(),
651 ))
652 } else {
653 None
654 };
655
656 let key = this.machine.tls.create_tls_key(dtor, dest.layout.size)?;
657 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
658 }
659 "FlsGetValue" => {
660 let [key] = this.check_shim_sig(
662 shim_sig!(extern "system" fn(u32) -> *_),
663 (link_name, abi, args),
664 )?;
665 let key = u128::from(this.read_scalar(key)?.to_u32()?);
666 let active_thread = this.active_thread();
667 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
668 this.write_scalar(ptr, dest)?;
669 }
670 "FlsSetValue" => {
671 let [key, new_ptr] = this.check_shim_sig(
673 shim_sig!(extern "system" fn(u32, *_) -> winapi::BOOL),
674 (link_name, abi, args),
675 )?;
676 let key = u128::from(this.read_scalar(key)?.to_u32()?);
677 let active_thread = this.active_thread();
678 let new_data = this.read_scalar(new_ptr)?;
679 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
680
681 this.write_int(1, dest)?;
683 }
684 "FlsFree" => {
685 let [key] = this.check_shim_sig(
687 shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
688 (link_name, abi, args),
689 )?;
690 let key = u128::from(this.read_scalar(key)?.to_u32()?);
691 let tls_entry = this.machine.tls.delete_tls_key(key)?;
692
693 if !tls_entry.data.is_empty() && tls_entry.dtor.is_some() {
695 throw_unsup_format!(
696 "calling `FlsFree` on a key with an associated dtor is not supported"
697 );
698 }
699
700 this.write_int(1, dest)?;
702 }
703 "IsThreadAFiber" => {
704 let [] = this.check_shim_sig(
706 shim_sig!(extern "system" fn() -> winapi::BOOL),
707 (link_name, abi, args),
708 )?;
709
710 this.write_int(0, dest)?;
712 }
713
714 "GetCommandLineW" => {
716 let [] = this.check_shim_sig(
718 shim_sig!(extern "system" fn() -> *_),
719 (link_name, abi, args),
720 )?;
721 this.write_pointer(
722 this.machine.cmd_line.expect("machine must be initialized"),
723 dest,
724 )?;
725 }
726
727 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
729 let [filetime] = this.check_shim_sig(
731 shim_sig!(extern "system" fn(*_) -> ()),
732 (link_name, abi, args),
733 )?;
734 this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?;
735 }
736 "QueryPerformanceCounter" => {
737 let [performance_count] = this.check_shim_sig(
739 shim_sig!(extern "system" fn(*_) -> winapi::BOOL),
740 (link_name, abi, args),
741 )?;
742 let result = this.QueryPerformanceCounter(performance_count)?;
743 this.write_scalar(result, dest)?;
744 }
745 "QueryPerformanceFrequency" => {
746 let [frequency] = this.check_shim_sig(
748 shim_sig!(extern "system" fn(*_) -> winapi::BOOL),
749 (link_name, abi, args),
750 )?;
751 let result = this.QueryPerformanceFrequency(frequency)?;
752 this.write_scalar(result, dest)?;
753 }
754 "Sleep" => {
755 let [timeout] = this.check_shim_sig(
757 shim_sig!(extern "system" fn(u32) -> ()),
758 (link_name, abi, args),
759 )?;
760
761 this.Sleep(timeout)?;
762 }
763 "CreateWaitableTimerExW" => {
764 let [attributes, name, flags, access] = this.check_shim_sig(
766 shim_sig!(extern "system" fn(*_, *_, u32, u32) -> winapi::HANDLE),
767 (link_name, abi, args),
768 )?;
769 this.read_pointer(attributes)?;
770 this.read_pointer(name)?;
771 this.read_scalar(flags)?.to_u32()?;
772 this.read_scalar(access)?.to_u32()?;
773 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
775 this.set_last_error(not_supported)?;
776 this.write_null(dest)?;
777 }
778
779 "InitOnceBeginInitialize" => {
781 let [ptr, flags, pending, context] = this.check_shim_sig(
782 shim_sig!(extern "system" fn(*_, u32, *_, *_) -> winapi::BOOL),
783 (link_name, abi, args),
784 )?;
785 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
786 }
787 "InitOnceComplete" => {
788 let [ptr, flags, context] = this.check_shim_sig(
789 shim_sig!(extern "system" fn(*_, u32, *_) -> winapi::BOOL),
790 (link_name, abi, args),
791 )?;
792 let result = this.InitOnceComplete(ptr, flags, context)?;
793 this.write_scalar(result, dest)?;
794 }
795 "WaitOnAddress" => {
796 let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig(
798 shim_sig!(extern "system" fn(*_, *_, usize, u32) -> winapi::BOOL),
800 (link_name, abi, args),
801 )?;
802
803 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
804 }
805 "WakeByAddressSingle" => {
806 let [ptr_op] = this.check_shim_sig(
808 shim_sig!(extern "system" fn(*_) -> ()),
809 (link_name, abi, 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(*_) -> ()),
818 (link_name, abi, args),
819 )?;
820
821 this.WakeByAddressAll(ptr_op)?;
822 }
823
824 "GetProcAddress" => {
826 let [module, proc_name] = this.check_shim_sig(
828 shim_sig!(extern "system" fn(winapi::HMODULE, *_) -> winapi::FARPROC),
829 (link_name, abi, args),
830 )?;
831 this.read_target_isize(module)?;
832 let name = this.read_c_str(this.read_pointer(proc_name)?)?;
833 if let Ok(name) = str::from_utf8(name)
834 && is_dyn_sym(name)
835 {
836 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
837 this.write_pointer(ptr, dest)?;
838 } else {
839 this.write_null(dest)?;
840 }
841 }
842
843 "CreateThread" => {
845 let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig(
846 shim_sig!(
847 extern "system" fn(
848 *_,
849 usize,
850 *_,
851 *_,
852 u32,
853 *_,
854 ) -> winapi::HANDLE
855 ),
856 (link_name, abi, args),
857 )?;
858
859 let thread_id =
860 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
861
862 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
863 }
864 "WaitForSingleObject" => {
865 let [handle, timeout] = this.check_shim_sig(
866 shim_sig!(extern "system" fn(winapi::HANDLE, u32) -> u32),
867 (link_name, abi, args),
868 )?;
869
870 this.WaitForSingleObject(handle, timeout, dest)?;
871 }
872 "GetCurrentProcess" => {
873 let [] = this.check_shim_sig(
874 shim_sig!(extern "system" fn() -> winapi::HANDLE),
875 (link_name, abi, args),
876 )?;
877
878 this.write_scalar(
879 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
880 dest,
881 )?;
882 }
883 "GetCurrentThread" => {
884 let [] = this.check_shim_sig(
885 shim_sig!(extern "system" fn() -> winapi::HANDLE),
886 (link_name, abi, args),
887 )?;
888
889 this.write_scalar(
890 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
891 dest,
892 )?;
893 }
894 "SetThreadDescription" => {
895 let [handle, name] = this.check_shim_sig(
896 shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> i32),
897 (link_name, abi, args),
898 )?;
899
900 let handle = this.read_handle(handle, "SetThreadDescription")?;
901 let name = this.read_wide_str(this.read_pointer(name)?)?;
902
903 let thread = match handle {
904 Handle::Thread(thread) => thread,
905 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
906 _ => this.invalid_handle("SetThreadDescription")?,
907 };
908 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
910 this.write_scalar(Scalar::from_u32(0), dest)?;
911 }
912 "GetThreadDescription" => {
913 let [handle, name_ptr] = this.check_shim_sig(
914 shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> i32),
915 (link_name, abi, args),
916 )?;
917
918 let handle = this.read_handle(handle, "GetThreadDescription")?;
919 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
922 Handle::Thread(thread) => thread,
923 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
924 _ => this.invalid_handle("GetThreadDescription")?,
925 };
926 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
928 let name = this.alloc_os_str_as_wide_str(
929 bytes_to_os_str(&name)?,
930 MiriMemoryKind::WinLocal.into(),
931 )?;
932 let name = Scalar::from_maybe_pointer(name, this);
933 let res = Scalar::from_u32(0);
934
935 this.write_scalar(name, &name_ptr)?;
936 this.write_scalar(res, dest)?;
937 }
938 "GetThreadId" => {
939 let [handle] = this.check_shim_sig(
940 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
941 (link_name, abi, args),
942 )?;
943 let handle = this.read_handle(handle, "GetThreadId")?;
944 let thread = match handle {
945 Handle::Thread(thread) => thread,
946 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
947 _ => this.invalid_handle("GetThreadDescription")?,
948 };
949 this.write_scalar(Scalar::from_u32(thread.to_u32()), dest)?;
950 }
951 "GetCurrentThreadId" => {
952 let [] = this.check_shim_sig(
953 shim_sig!(extern "system" fn() -> u32),
954 (link_name, abi, args),
955 )?;
956 this.write_scalar(Scalar::from_u32(this.active_thread().to_u32()), dest)?;
957 }
958
959 "ExitProcess" => {
961 let [code] = this.check_shim_sig(
963 shim_sig!(extern "system" fn(u32) -> ()),
964 (link_name, abi, args),
965 )?;
966 let code = this.read_scalar(code)?.to_i32()?;
968 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
969 }
970 "SystemFunction036" => {
971 let [ptr, len] = this.check_shim_sig(
974 shim_sig!(extern "system" fn(*_, u32) -> u8),
976 (link_name, abi, args),
977 )?;
978 let ptr = this.read_pointer(ptr)?;
979 let len = this.read_scalar(len)?.to_u32()?;
980 this.gen_random(ptr, len.into())?;
981 this.write_scalar(Scalar::from_bool(true), dest)?;
982 }
983 "ProcessPrng" => {
984 let [ptr, len] = this.check_shim_sig(
987 shim_sig!(extern "system" fn(*_, usize) -> winapi::BOOL),
988 (link_name, abi, args),
989 )?;
990 let ptr = this.read_pointer(ptr)?;
991 let len = this.read_target_usize(len)?;
992 this.gen_random(ptr, len)?;
993 this.write_int(1, dest)?;
994 }
995 "BCryptGenRandom" => {
996 let [algorithm, ptr, len, flags] = this.check_shim_sig(
998 shim_sig!(extern "system" fn(*_, *_, u32, u32) -> i32),
999 (link_name, abi, args),
1000 )?;
1001 let algorithm = this.read_scalar(algorithm)?;
1002 let algorithm = algorithm.to_target_usize(this)?;
1003 let ptr = this.read_pointer(ptr)?;
1004 let len = this.read_scalar(len)?.to_u32()?;
1005 let flags = this.read_scalar(flags)?.to_u32()?;
1006 match flags {
1007 0 => {
1008 if algorithm != 0x81 {
1009 throw_unsup_format!(
1011 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
1012 );
1013 }
1014 }
1015 2 => {
1016 if algorithm != 0 {
1018 throw_unsup_format!(
1019 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
1020 );
1021 }
1022 }
1023 _ => {
1024 throw_unsup_format!(
1025 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
1026 );
1027 }
1028 }
1029 this.gen_random(ptr, len.into())?;
1030 this.write_null(dest)?; }
1032 "GetConsoleScreenBufferInfo" => {
1033 let [console, buffer_info] = this.check_shim_sig(
1036 shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> winapi::BOOL),
1037 (link_name, abi, args),
1038 )?;
1039 this.read_target_isize(console)?;
1040 this.deref_pointer(buffer_info)?;
1042 this.write_null(dest)?;
1045 }
1046 "GetStdHandle" => {
1047 let [which] = this.check_shim_sig(
1049 shim_sig!(extern "system" fn(u32) -> winapi::HANDLE),
1050 (link_name, abi, args),
1051 )?;
1052 let res = this.GetStdHandle(which)?;
1053 this.write_scalar(res, dest)?;
1054 }
1055 "DuplicateHandle" => {
1056 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
1057 this.check_shim_sig(
1058 shim_sig!(
1059 extern "system" fn(
1060 winapi::HANDLE,
1061 winapi::HANDLE,
1062 winapi::HANDLE,
1063 *_,
1064 u32,
1065 winapi::BOOL,
1066 u32,
1067 ) -> winapi::BOOL
1068 ),
1069 (link_name, abi, args),
1070 )?;
1071 let res = this.DuplicateHandle(
1072 src_proc,
1073 src_handle,
1074 target_proc,
1075 target_handle,
1076 access,
1077 inherit,
1078 options,
1079 )?;
1080 this.write_scalar(res, dest)?;
1081 }
1082 "CloseHandle" => {
1083 let [handle] = this.check_shim_sig(
1084 shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
1085 (link_name, abi, args),
1086 )?;
1087
1088 let ret = this.CloseHandle(handle)?;
1089
1090 this.write_scalar(ret, dest)?;
1091 }
1092 "GetModuleFileNameW" => {
1093 let [handle, filename, size] = this.check_shim_sig(
1095 shim_sig!(extern "system" fn(winapi::HMODULE, *_, u32) -> u32),
1096 (link_name, abi, args),
1097 )?;
1098 this.check_no_isolation("`GetModuleFileNameW`")?;
1099
1100 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
1101 let filename = this.read_pointer(filename)?;
1102 let size = this.read_scalar(size)?.to_u32()?;
1103
1104 if handle != Handle::Null {
1105 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
1106 }
1107
1108 let path = std::env::current_exe().unwrap();
1111 let (all_written, size_needed) =
1112 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
1113
1114 if all_written {
1115 this.write_int(size_needed.strict_sub(1), dest)?;
1119 } else {
1120 this.write_int(size, dest)?;
1125 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
1126 this.set_last_error(insufficient_buffer)?;
1127 }
1128 }
1129 "FormatMessageW" => {
1130 let [flags, module, message_id, language_id, buffer, size, arguments] = this
1132 .check_shim_sig(
1133 shim_sig!(
1134 extern "system" fn(u32, *_, u32, u32, *_, u32, *_) -> u32
1135 ),
1136 (link_name, abi, args),
1137 )?;
1138
1139 let flags = this.read_scalar(flags)?.to_u32()?;
1140 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
1142 let _language_id = this.read_scalar(language_id)?.to_u32()?;
1143 let buffer = this.read_pointer(buffer)?;
1144 let size = this.read_scalar(size)?.to_u32()?;
1145 let _arguments = this.read_pointer(arguments)?;
1146
1147 if flags != 4096u32 | 512u32 {
1150 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
1151 }
1152
1153 let error = this.try_errnum_to_io_error(message_id)?;
1154 let formatted = match error {
1155 Some(err) => format!("{err}"),
1156 None => format!("<unknown error in FormatMessageW: {message_id}>"),
1157 };
1158 let (complete, length) =
1159 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
1160 if !complete {
1161 throw_unsup_format!("FormatMessageW: buffer not big enough");
1164 }
1165 this.write_int(length.strict_sub(1), dest)?;
1167 }
1168
1169 "_Unwind_RaiseException" => {
1170 if this.tcx.sess.target.env != Env::Gnu {
1175 throw_unsup_format!(
1176 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
1177 );
1178 }
1179 let [payload] = this.check_shim_sig(
1181 shim_sig!(extern "C" fn(*_) -> panic_unwind::imp::uw::_Unwind_Reason_Code),
1184 (link_name, abi, args),
1185 )?;
1186 this.handle_miri_start_unwind(payload)?;
1187 return interp_ok(EmulateItemResult::NeedsUnwind);
1188 }
1189
1190 "GetProcessHeap" if this.frame_in_std() => {
1193 let [] = this.check_shim_sig(
1194 shim_sig!(extern "system" fn() -> winapi::HANDLE),
1195 (link_name, abi, args),
1196 )?;
1197 this.write_int(1, dest)?;
1200 }
1201 "GetModuleHandleA" if this.frame_in_std() => {
1202 let [_module_name] = this.check_shim_sig(
1203 shim_sig!(extern "system" fn(*_) -> winapi::HMODULE),
1204 (link_name, abi, args),
1205 )?;
1206 this.write_int(1, dest)?;
1208 }
1209 "SetConsoleTextAttribute" if this.frame_in_std() => {
1210 let [_console_output, _attribute] = this.check_shim_sig(
1211 shim_sig!(extern "system" fn(winapi::HANDLE, u16) -> winapi::BOOL),
1212 (link_name, abi, args),
1213 )?;
1214 this.write_null(dest)?;
1216 }
1217 "GetConsoleMode" if this.frame_in_std() => {
1218 let [console, mode] = this.check_shim_sig(
1219 shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> winapi::BOOL),
1220 (link_name, abi, args),
1221 )?;
1222 this.read_target_isize(console)?;
1223 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
1224 this.write_null(dest)?;
1226 }
1227 "GetFileType" if this.frame_in_std() => {
1228 let [_file] = this.check_shim_sig(
1229 shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
1230 (link_name, abi, args),
1231 )?;
1232 this.write_null(dest)?;
1234 }
1235 "AddVectoredExceptionHandler" if this.frame_in_std() => {
1236 let [_first, _handler] = this.check_shim_sig(
1237 shim_sig!(extern "system" fn(u32, *_) -> *_),
1238 (link_name, abi, args),
1239 )?;
1240 this.write_int(1, dest)?;
1242 }
1243 "SetThreadStackGuarantee" if this.frame_in_std() => {
1244 let [_stack_size_in_bytes] = this.check_shim_sig(
1245 shim_sig!(extern "system" fn(*_) -> winapi::BOOL),
1246 (link_name, abi, args),
1247 )?;
1248 this.write_int(1, dest)?;
1250 }
1251 "SwitchToThread" if this.frame_in_std() => {
1253 let [] = this.check_shim_sig(
1254 shim_sig!(extern "system" fn() -> winapi::BOOL),
1255 (link_name, abi, args),
1256 )?;
1257
1258 this.yield_active_thread();
1259
1260 this.write_null(dest)?;
1262 }
1263
1264 _ => return interp_ok(EmulateItemResult::NotSupported),
1265 }
1266
1267 interp_ok(EmulateItemResult::NeedsReturn)
1268 }
1269}