1use std::ffi::OsStr;
2use std::path::{self, Path, PathBuf};
3use std::{io, iter, str};
4
5use rustc_abi::{Align, CanonAbi, Size, X86Call};
6use rustc_middle::ty::Ty;
7use rustc_span::Symbol;
8use rustc_target::callconv::FnAbi;
9
10use self::shims::windows::handle::{Handle, PseudoHandle};
11use crate::shims::os_str::bytes_to_os_str;
12use crate::shims::windows::*;
13use crate::*;
14
15pub fn is_dyn_sym(name: &str) -> bool {
16 matches!(
18 name,
19 "SetThreadDescription" | "GetThreadDescription" | "WaitOnAddress" | "WakeByAddressSingle"
20 )
21}
22
23#[cfg(windows)]
24fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
25 interp_ok(path::absolute(path))
27}
28
29#[cfg(unix)]
30#[expect(clippy::get_first, clippy::arithmetic_side_effects)]
31fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<PathBuf>> {
32 use std::sync::LazyLock;
33
34 use rustc_data_structures::fx::FxHashSet;
35
36 let bytes = path.as_os_str().as_encoded_bytes();
44 if bytes.get(0).copied() == Some(b'/')
47 && bytes.get(1).copied() == Some(b'/')
48 && matches!(bytes.get(2), Some(b'.' | b'?'))
49 && bytes.get(3).copied() == Some(b'/')
50 {
51 return interp_ok(Ok(path.into()));
52 };
53 let is_unc = bytes.starts_with(b"//");
54 static MAGIC_FILENAMES: LazyLock<FxHashSet<&'static str>> = LazyLock::new(|| {
56 FxHashSet::from_iter([
57 "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
58 "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
59 ])
60 });
61 if str::from_utf8(bytes).is_ok_and(|s| MAGIC_FILENAMES.contains(&*s.to_ascii_uppercase())) {
62 let mut result: Vec<u8> = b"//./".into();
63 result.extend(bytes);
64 return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
65 }
66 let mut result: Vec<&[u8]> = vec![]; let mut bytes = bytes; let mut stop = false;
71 while !stop {
72 let mut component = match bytes.iter().position(|&b| b == b'/') {
74 Some(pos) => {
75 let (component, tail) = bytes.split_at(pos);
76 bytes = &tail[1..]; component
78 }
79 None => {
80 stop = true;
82 let component = bytes;
83 bytes = &[];
84 component
85 }
86 };
87 if !is_unc && component.eq_ignore_ascii_case(b"NUL") {
91 let mut result: Vec<u8> = b"//./".into();
92 result.extend(component);
93 return interp_ok(Ok(bytes_to_os_str(&result)?.into()));
94 }
95 if component == b".." {
97 let is_root = {
99 result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':'])
101 } || {
102 result.len() == 4 && matches!(result[0], []) && matches!(result[1], [])
104 };
105 if !is_root {
106 result.pop();
107 }
108 continue;
109 }
110 let len = component.len();
113 if !is_unc && len >= 2 && component[len - 1] == b'.' && component[len - 2] != b'.' {
114 component = &component[..len - 1];
115 }
116 result.push(component);
118 }
119 if result.len() == 2 && matches!(result[0], []) && matches!(result[1], [_, b':']) {
121 result.push(&[]);
122 }
123 let result = result.join(&b'/');
125 interp_ok(path::absolute(bytes_to_os_str(&result)?))
126}
127
128impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
129pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
130 fn emulate_foreign_item_inner(
131 &mut self,
132 link_name: Symbol,
133 abi: &FnAbi<'tcx, Ty<'tcx>>,
134 args: &[OpTy<'tcx>],
135 dest: &MPlaceTy<'tcx>,
136 ) -> InterpResult<'tcx, EmulateItemResult> {
137 let this = self.eval_context_mut();
138
139 let sys_conv = if this.tcx.sess.target.arch == "x86" {
144 CanonAbi::X86(X86Call::Stdcall)
145 } else {
146 CanonAbi::C
147 };
148
149 match link_name.as_str() {
158 "GetEnvironmentVariableW" => {
160 let [name, buf, size] =
161 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
162 let result = this.GetEnvironmentVariableW(name, buf, size)?;
163 this.write_scalar(result, dest)?;
164 }
165 "SetEnvironmentVariableW" => {
166 let [name, value] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
167 let result = this.SetEnvironmentVariableW(name, value)?;
168 this.write_scalar(result, dest)?;
169 }
170 "GetEnvironmentStringsW" => {
171 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
172 let result = this.GetEnvironmentStringsW()?;
173 this.write_pointer(result, dest)?;
174 }
175 "FreeEnvironmentStringsW" => {
176 let [env_block] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
177 let result = this.FreeEnvironmentStringsW(env_block)?;
178 this.write_scalar(result, dest)?;
179 }
180 "GetCurrentDirectoryW" => {
181 let [size, buf] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
182 let result = this.GetCurrentDirectoryW(size, buf)?;
183 this.write_scalar(result, dest)?;
184 }
185 "SetCurrentDirectoryW" => {
186 let [path] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
187 let result = this.SetCurrentDirectoryW(path)?;
188 this.write_scalar(result, dest)?;
189 }
190 "GetUserProfileDirectoryW" => {
191 let [token, buf, size] =
192 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
193 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
194 this.write_scalar(result, dest)?;
195 }
196 "GetCurrentProcessId" => {
197 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
198 let result = this.GetCurrentProcessId()?;
199 this.write_scalar(result, dest)?;
200 }
201
202 "NtWriteFile" => {
204 let [
205 handle,
206 event,
207 apc_routine,
208 apc_context,
209 io_status_block,
210 buf,
211 n,
212 byte_offset,
213 key,
214 ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
215 this.NtWriteFile(
216 handle,
217 event,
218 apc_routine,
219 apc_context,
220 io_status_block,
221 buf,
222 n,
223 byte_offset,
224 key,
225 dest,
226 )?;
227 }
228 "NtReadFile" => {
229 let [
230 handle,
231 event,
232 apc_routine,
233 apc_context,
234 io_status_block,
235 buf,
236 n,
237 byte_offset,
238 key,
239 ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
240 this.NtReadFile(
241 handle,
242 event,
243 apc_routine,
244 apc_context,
245 io_status_block,
246 buf,
247 n,
248 byte_offset,
249 key,
250 dest,
251 )?;
252 }
253 "GetFullPathNameW" => {
254 let [filename, size, buffer, filepart] =
255 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
256 this.check_no_isolation("`GetFullPathNameW`")?;
257
258 let filename = this.read_pointer(filename)?;
259 let size = this.read_scalar(size)?.to_u32()?;
260 let buffer = this.read_pointer(buffer)?;
261 let filepart = this.read_pointer(filepart)?;
262
263 if !this.ptr_is_null(filepart)? {
264 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
265 }
266
267 let filename = this.read_path_from_wide_str(filename)?;
268 let result = match win_get_full_path_name(&filename)? {
269 Err(err) => {
270 this.set_last_error(err)?;
271 Scalar::from_u32(0) }
273 Ok(abs_filename) => {
274 Scalar::from_u32(helpers::windows_check_buffer_size(
275 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
276 ))
277 }
280 };
281 this.write_scalar(result, dest)?;
282 }
283 "CreateFileW" => {
284 let [
285 file_name,
286 desired_access,
287 share_mode,
288 security_attributes,
289 creation_disposition,
290 flags_and_attributes,
291 template_file,
292 ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
293 let handle = this.CreateFileW(
294 file_name,
295 desired_access,
296 share_mode,
297 security_attributes,
298 creation_disposition,
299 flags_and_attributes,
300 template_file,
301 )?;
302 this.write_scalar(handle.to_scalar(this), dest)?;
303 }
304 "GetFileInformationByHandle" => {
305 let [handle, info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
306 let res = this.GetFileInformationByHandle(handle, info)?;
307 this.write_scalar(res, dest)?;
308 }
309 "DeleteFileW" => {
310 let [file_name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
311 let res = this.DeleteFileW(file_name)?;
312 this.write_scalar(res, dest)?;
313 }
314 "SetFilePointerEx" => {
315 let [file, distance_to_move, new_file_pointer, move_method] =
316 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
317 let res =
318 this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
319 this.write_scalar(res, dest)?;
320 }
321
322 "HeapAlloc" => {
324 let [handle, flags, size] =
325 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
326 this.read_target_isize(handle)?;
327 let flags = this.read_scalar(flags)?.to_u32()?;
328 let size = this.read_target_usize(size)?;
329 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
330 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
331 AllocInit::Zero
332 } else {
333 AllocInit::Uninit
334 };
335 let align = this.tcx.pointer_size().bytes().strict_mul(2);
338 let ptr = this.allocate_ptr(
339 Size::from_bytes(size),
340 Align::from_bytes(align).unwrap(),
341 MiriMemoryKind::WinHeap.into(),
342 init,
343 )?;
344 this.write_pointer(ptr, dest)?;
345 }
346 "HeapFree" => {
347 let [handle, flags, ptr] =
348 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
349 this.read_target_isize(handle)?;
350 this.read_scalar(flags)?.to_u32()?;
351 let ptr = this.read_pointer(ptr)?;
352 if !this.ptr_is_null(ptr)? {
355 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
356 }
357 this.write_scalar(Scalar::from_i32(1), dest)?;
358 }
359 "HeapReAlloc" => {
360 let [handle, flags, old_ptr, size] =
361 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
362 this.read_target_isize(handle)?;
363 this.read_scalar(flags)?.to_u32()?;
364 let old_ptr = this.read_pointer(old_ptr)?;
365 let size = this.read_target_usize(size)?;
366 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
371 old_ptr,
372 None,
373 Size::from_bytes(size),
374 Align::from_bytes(align).unwrap(),
375 MiriMemoryKind::WinHeap.into(),
376 AllocInit::Uninit,
377 )?;
378 this.write_pointer(new_ptr, dest)?;
379 }
380 "LocalFree" => {
381 let [ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
382 let ptr = this.read_pointer(ptr)?;
383 if !this.ptr_is_null(ptr)? {
386 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
387 }
388 this.write_null(dest)?;
389 }
390
391 "SetLastError" => {
393 let [error] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
394 let error = this.read_scalar(error)?;
395 this.set_last_error(error)?;
396 }
397 "GetLastError" => {
398 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
399 let last_error = this.get_last_error()?;
400 this.write_scalar(last_error, dest)?;
401 }
402 "RtlNtStatusToDosError" => {
403 let [status] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
404 let status = this.read_scalar(status)?.to_u32()?;
405 let err = match status {
406 0xC00000A2 => 19,
408 0xC0000098 => 1006,
410 0xC000007F => 112,
412 0xC0000185 => 1117,
414 0xC0000022 => 5,
416 _ => 317,
418 };
419 this.write_scalar(Scalar::from_i32(err), dest)?;
420 }
421
422 "GetSystemInfo" => {
424 let [system_info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
426 let system_info =
427 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
428 this.write_bytes_ptr(
430 system_info.ptr(),
431 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
432 )?;
433 this.write_int_fields_named(
435 &[
436 ("dwPageSize", this.machine.page_size.into()),
437 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
438 ],
439 &system_info,
440 )?;
441 }
442
443 "TlsAlloc" => {
445 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
449 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
450 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
451 }
452 "TlsGetValue" => {
453 let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
454 let key = u128::from(this.read_scalar(key)?.to_u32()?);
455 let active_thread = this.active_thread();
456 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
457 this.write_scalar(ptr, dest)?;
458 }
459 "TlsSetValue" => {
460 let [key, new_ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
461 let key = u128::from(this.read_scalar(key)?.to_u32()?);
462 let active_thread = this.active_thread();
463 let new_data = this.read_scalar(new_ptr)?;
464 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
465
466 this.write_int(1, dest)?;
468 }
469 "TlsFree" => {
470 let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
471 let key = u128::from(this.read_scalar(key)?.to_u32()?);
472 this.machine.tls.delete_tls_key(key)?;
473
474 this.write_int(1, dest)?;
476 }
477
478 "GetCommandLineW" => {
480 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
481 this.write_pointer(
482 this.machine.cmd_line.expect("machine must be initialized"),
483 dest,
484 )?;
485 }
486
487 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
489 #[allow(non_snake_case)]
490 let [LPFILETIME] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
491 this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
492 }
493 "QueryPerformanceCounter" => {
494 #[allow(non_snake_case)]
495 let [lpPerformanceCount] =
496 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
497 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
498 this.write_scalar(result, dest)?;
499 }
500 "QueryPerformanceFrequency" => {
501 #[allow(non_snake_case)]
502 let [lpFrequency] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
503 let result = this.QueryPerformanceFrequency(lpFrequency)?;
504 this.write_scalar(result, dest)?;
505 }
506 "Sleep" => {
507 let [timeout] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
508
509 this.Sleep(timeout)?;
510 }
511 "CreateWaitableTimerExW" => {
512 let [attributes, name, flags, access] =
513 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
514 this.read_pointer(attributes)?;
515 this.read_pointer(name)?;
516 this.read_scalar(flags)?.to_u32()?;
517 this.read_scalar(access)?.to_u32()?;
518 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
520 this.set_last_error(not_supported)?;
521 this.write_null(dest)?;
522 }
523
524 "InitOnceBeginInitialize" => {
526 let [ptr, flags, pending, context] =
527 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
528 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
529 }
530 "InitOnceComplete" => {
531 let [ptr, flags, context] =
532 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
533 let result = this.InitOnceComplete(ptr, flags, context)?;
534 this.write_scalar(result, dest)?;
535 }
536 "WaitOnAddress" => {
537 let [ptr_op, compare_op, size_op, timeout_op] =
538 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
539
540 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
541 }
542 "WakeByAddressSingle" => {
543 let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
544
545 this.WakeByAddressSingle(ptr_op)?;
546 }
547 "WakeByAddressAll" => {
548 let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
549
550 this.WakeByAddressAll(ptr_op)?;
551 }
552
553 "GetProcAddress" => {
555 #[allow(non_snake_case)]
556 let [hModule, lpProcName] =
557 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
558 this.read_target_isize(hModule)?;
559 let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
560 if let Ok(name) = str::from_utf8(name)
561 && is_dyn_sym(name)
562 {
563 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
564 this.write_pointer(ptr, dest)?;
565 } else {
566 this.write_null(dest)?;
567 }
568 }
569
570 "CreateThread" => {
572 let [security, stacksize, start, arg, flags, thread] =
573 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
574
575 let thread_id =
576 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
577
578 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
579 }
580 "WaitForSingleObject" => {
581 let [handle, timeout] =
582 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
583
584 this.WaitForSingleObject(handle, timeout, dest)?;
585 }
586 "GetCurrentProcess" => {
587 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
588
589 this.write_scalar(
590 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
591 dest,
592 )?;
593 }
594 "GetCurrentThread" => {
595 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
596
597 this.write_scalar(
598 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
599 dest,
600 )?;
601 }
602 "SetThreadDescription" => {
603 let [handle, name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
604
605 let handle = this.read_handle(handle, "SetThreadDescription")?;
606 let name = this.read_wide_str(this.read_pointer(name)?)?;
607
608 let thread = match handle {
609 Handle::Thread(thread) => thread,
610 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
611 _ => this.invalid_handle("SetThreadDescription")?,
612 };
613 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
615 this.write_scalar(Scalar::from_u32(0), dest)?;
616 }
617 "GetThreadDescription" => {
618 let [handle, name_ptr] =
619 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
620
621 let handle = this.read_handle(handle, "GetThreadDescription")?;
622 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
625 Handle::Thread(thread) => thread,
626 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
627 _ => this.invalid_handle("GetThreadDescription")?,
628 };
629 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
631 let name = this.alloc_os_str_as_wide_str(
632 bytes_to_os_str(&name)?,
633 MiriMemoryKind::WinLocal.into(),
634 )?;
635 let name = Scalar::from_maybe_pointer(name, this);
636 let res = Scalar::from_u32(0);
637
638 this.write_scalar(name, &name_ptr)?;
639 this.write_scalar(res, dest)?;
640 }
641 "GetThreadId" => {
642 let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
643 let handle = this.read_handle(handle, "GetThreadId")?;
644 let thread = match handle {
645 Handle::Thread(thread) => thread,
646 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
647 _ => this.invalid_handle("GetThreadDescription")?,
648 };
649 let tid = this.get_tid(thread);
650 this.write_scalar(Scalar::from_u32(tid), dest)?;
651 }
652 "GetCurrentThreadId" => {
653 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
654 let thread = this.active_thread();
655 let tid = this.get_tid(thread);
656 this.write_scalar(Scalar::from_u32(tid), dest)?;
657 }
658
659 "ExitProcess" => {
661 let [code] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
662 let code = this.read_scalar(code)?.to_i32()?;
664 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
665 }
666 "SystemFunction036" => {
667 let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
670 let ptr = this.read_pointer(ptr)?;
671 let len = this.read_scalar(len)?.to_u32()?;
672 this.gen_random(ptr, len.into())?;
673 this.write_scalar(Scalar::from_bool(true), dest)?;
674 }
675 "ProcessPrng" => {
676 let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
678 let ptr = this.read_pointer(ptr)?;
679 let len = this.read_target_usize(len)?;
680 this.gen_random(ptr, len)?;
681 this.write_int(1, dest)?;
682 }
683 "BCryptGenRandom" => {
684 let [algorithm, ptr, len, flags] =
686 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
687 let algorithm = this.read_scalar(algorithm)?;
688 let algorithm = algorithm.to_target_usize(this)?;
689 let ptr = this.read_pointer(ptr)?;
690 let len = this.read_scalar(len)?.to_u32()?;
691 let flags = this.read_scalar(flags)?.to_u32()?;
692 match flags {
693 0 => {
694 if algorithm != 0x81 {
695 throw_unsup_format!(
697 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
698 );
699 }
700 }
701 2 => {
702 if algorithm != 0 {
704 throw_unsup_format!(
705 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
706 );
707 }
708 }
709 _ => {
710 throw_unsup_format!(
711 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
712 );
713 }
714 }
715 this.gen_random(ptr, len.into())?;
716 this.write_null(dest)?; }
718 "GetConsoleScreenBufferInfo" => {
719 let [console, buffer_info] =
721 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
722 this.read_target_isize(console)?;
723 this.deref_pointer(buffer_info)?;
725 this.write_null(dest)?;
728 }
729 "GetStdHandle" => {
730 let [which] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
731 let res = this.GetStdHandle(which)?;
732 this.write_scalar(res, dest)?;
733 }
734 "DuplicateHandle" => {
735 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
736 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
737 let res = this.DuplicateHandle(
738 src_proc,
739 src_handle,
740 target_proc,
741 target_handle,
742 access,
743 inherit,
744 options,
745 )?;
746 this.write_scalar(res, dest)?;
747 }
748 "CloseHandle" => {
749 let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
750
751 let ret = this.CloseHandle(handle)?;
752
753 this.write_scalar(ret, dest)?;
754 }
755 "GetModuleFileNameW" => {
756 let [handle, filename, size] =
757 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
758 this.check_no_isolation("`GetModuleFileNameW`")?;
759
760 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
761 let filename = this.read_pointer(filename)?;
762 let size = this.read_scalar(size)?.to_u32()?;
763
764 if handle != Handle::Null {
765 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
766 }
767
768 let path = std::env::current_exe().unwrap();
771 let (all_written, size_needed) =
772 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
773
774 if all_written {
775 this.write_int(size_needed.strict_sub(1), dest)?;
779 } else {
780 this.write_int(size, dest)?;
785 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
786 this.set_last_error(insufficient_buffer)?;
787 }
788 }
789 "FormatMessageW" => {
790 let [flags, module, message_id, language_id, buffer, size, arguments] =
791 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
792
793 let flags = this.read_scalar(flags)?.to_u32()?;
794 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
796 let _language_id = this.read_scalar(language_id)?.to_u32()?;
797 let buffer = this.read_pointer(buffer)?;
798 let size = this.read_scalar(size)?.to_u32()?;
799 let _arguments = this.read_pointer(arguments)?;
800
801 if flags != 4096u32 | 512u32 {
804 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
805 }
806
807 let error = this.try_errnum_to_io_error(message_id)?;
808 let formatted = match error {
809 Some(err) => format!("{err}"),
810 None => format!("<unknown error in FormatMessageW: {message_id}>"),
811 };
812 let (complete, length) =
813 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
814 if !complete {
815 throw_unsup_format!("FormatMessageW: buffer not big enough");
818 }
819 this.write_int(length.strict_sub(1), dest)?;
821 }
822
823 "GetProcessHeap" if this.frame_in_std() => {
826 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
827 this.write_int(1, dest)?;
830 }
831 "GetModuleHandleA" if this.frame_in_std() => {
832 #[allow(non_snake_case)]
833 let [_lpModuleName] =
834 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
835 this.write_int(1, dest)?;
837 }
838 "SetConsoleTextAttribute" if this.frame_in_std() => {
839 #[allow(non_snake_case)]
840 let [_hConsoleOutput, _wAttribute] =
841 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
842 this.write_null(dest)?;
844 }
845 "GetConsoleMode" if this.frame_in_std() => {
846 let [console, mode] =
847 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
848 this.read_target_isize(console)?;
849 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
850 this.write_null(dest)?;
852 }
853 "GetFileType" if this.frame_in_std() => {
854 #[allow(non_snake_case)]
855 let [_hFile] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
856 this.write_null(dest)?;
858 }
859 "AddVectoredExceptionHandler" if this.frame_in_std() => {
860 #[allow(non_snake_case)]
861 let [_First, _Handler] =
862 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
863 this.write_int(1, dest)?;
865 }
866 "SetThreadStackGuarantee" if this.frame_in_std() => {
867 #[allow(non_snake_case)]
868 let [_StackSizeInBytes] =
869 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
870 this.write_int(1, dest)?;
872 }
873 "SwitchToThread" if this.frame_in_std() => {
875 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
876
877 this.yield_active_thread();
878
879 this.write_null(dest)?;
881 }
882
883 "_Unwind_RaiseException" => {
884 if this.tcx.sess.target.env != "gnu" {
889 throw_unsup_format!(
890 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
891 );
892 }
893 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
895 this.handle_miri_start_unwind(payload)?;
896 return interp_ok(EmulateItemResult::NeedsUnwind);
897 }
898
899 _ => return interp_ok(EmulateItemResult::NotSupported),
900 }
901
902 interp_ok(EmulateItemResult::NeedsReturn)
903 }
904}