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