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;
9use rustc_target::spec::{Arch, 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 let sys_conv = if this.tcx.sess.target.arch == Arch::X86 {
145 CanonAbi::X86(X86Call::Stdcall)
146 } else {
147 CanonAbi::C
148 };
149
150 match link_name.as_str() {
159 "GetEnvironmentVariableW" => {
161 let [name, buf, size] =
162 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
163 let result = this.GetEnvironmentVariableW(name, buf, size)?;
164 this.write_scalar(result, dest)?;
165 }
166 "SetEnvironmentVariableW" => {
167 let [name, value] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
168 let result = this.SetEnvironmentVariableW(name, value)?;
169 this.write_scalar(result, dest)?;
170 }
171 "GetEnvironmentStringsW" => {
172 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
173 let result = this.GetEnvironmentStringsW()?;
174 this.write_pointer(result, dest)?;
175 }
176 "FreeEnvironmentStringsW" => {
177 let [env_block] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
178 let result = this.FreeEnvironmentStringsW(env_block)?;
179 this.write_scalar(result, dest)?;
180 }
181 "GetCurrentDirectoryW" => {
182 let [size, buf] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
183 let result = this.GetCurrentDirectoryW(size, buf)?;
184 this.write_scalar(result, dest)?;
185 }
186 "SetCurrentDirectoryW" => {
187 let [path] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
188 let result = this.SetCurrentDirectoryW(path)?;
189 this.write_scalar(result, dest)?;
190 }
191 "GetUserProfileDirectoryW" => {
192 let [token, buf, size] =
193 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
194 let result = this.GetUserProfileDirectoryW(token, buf, size)?;
195 this.write_scalar(result, dest)?;
196 }
197 "GetCurrentProcessId" => {
198 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
199 let result = this.GetCurrentProcessId()?;
200 this.write_scalar(result, dest)?;
201 }
202
203 "NtWriteFile" => {
205 let [
206 handle,
207 event,
208 apc_routine,
209 apc_context,
210 io_status_block,
211 buf,
212 n,
213 byte_offset,
214 key,
215 ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
216 this.NtWriteFile(
217 handle,
218 event,
219 apc_routine,
220 apc_context,
221 io_status_block,
222 buf,
223 n,
224 byte_offset,
225 key,
226 dest,
227 )?;
228 }
229 "NtReadFile" => {
230 let [
231 handle,
232 event,
233 apc_routine,
234 apc_context,
235 io_status_block,
236 buf,
237 n,
238 byte_offset,
239 key,
240 ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
241 this.NtReadFile(
242 handle,
243 event,
244 apc_routine,
245 apc_context,
246 io_status_block,
247 buf,
248 n,
249 byte_offset,
250 key,
251 dest,
252 )?;
253 }
254 "GetFullPathNameW" => {
255 let [filename, size, buffer, filepart] =
256 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
257 this.check_no_isolation("`GetFullPathNameW`")?;
258
259 let filename = this.read_pointer(filename)?;
260 let size = this.read_scalar(size)?.to_u32()?;
261 let buffer = this.read_pointer(buffer)?;
262 let filepart = this.read_pointer(filepart)?;
263
264 if !this.ptr_is_null(filepart)? {
265 throw_unsup_format!("GetFullPathNameW: non-null `lpFilePart` is not supported");
266 }
267
268 let filename = this.read_path_from_wide_str(filename)?;
269 let result = match win_get_full_path_name(&filename)? {
270 Err(err) => {
271 this.set_last_error(err)?;
272 Scalar::from_u32(0) }
274 Ok(abs_filename) => {
275 Scalar::from_u32(helpers::windows_check_buffer_size(
276 this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
277 ))
278 }
281 };
282 this.write_scalar(result, dest)?;
283 }
284 "CreateFileW" => {
285 let [
286 file_name,
287 desired_access,
288 share_mode,
289 security_attributes,
290 creation_disposition,
291 flags_and_attributes,
292 template_file,
293 ] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
294 let handle = this.CreateFileW(
295 file_name,
296 desired_access,
297 share_mode,
298 security_attributes,
299 creation_disposition,
300 flags_and_attributes,
301 template_file,
302 )?;
303 this.write_scalar(handle.to_scalar(this), dest)?;
304 }
305 "GetFileInformationByHandle" => {
306 let [handle, info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
307 let res = this.GetFileInformationByHandle(handle, info)?;
308 this.write_scalar(res, dest)?;
309 }
310 "SetFileInformationByHandle" => {
311 let [handle, class, info, size] =
312 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
313 let res = this.SetFileInformationByHandle(handle, class, info, size)?;
314 this.write_scalar(res, dest)?;
315 }
316 "FlushFileBuffers" => {
317 let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
318 let res = this.FlushFileBuffers(handle)?;
319 this.write_scalar(res, dest)?;
320 }
321 "DeleteFileW" => {
322 let [file_name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
323 let res = this.DeleteFileW(file_name)?;
324 this.write_scalar(res, dest)?;
325 }
326 "SetFilePointerEx" => {
327 let [file, distance_to_move, new_file_pointer, move_method] =
328 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
329 let res =
330 this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
331 this.write_scalar(res, dest)?;
332 }
333
334 "HeapAlloc" => {
336 let [handle, flags, size] =
337 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
338 this.read_target_isize(handle)?;
339 let flags = this.read_scalar(flags)?.to_u32()?;
340 let size = this.read_target_usize(size)?;
341 const HEAP_ZERO_MEMORY: u32 = 0x00000008;
342 let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
343 AllocInit::Zero
344 } else {
345 AllocInit::Uninit
346 };
347 let align = this.tcx.pointer_size().bytes().strict_mul(2);
350 let ptr = this.allocate_ptr(
351 Size::from_bytes(size),
352 Align::from_bytes(align).unwrap(),
353 MiriMemoryKind::WinHeap.into(),
354 init,
355 )?;
356 this.write_pointer(ptr, dest)?;
357 }
358 "HeapFree" => {
359 let [handle, flags, ptr] =
360 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
361 this.read_target_isize(handle)?;
362 this.read_scalar(flags)?.to_u32()?;
363 let ptr = this.read_pointer(ptr)?;
364 if !this.ptr_is_null(ptr)? {
367 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
368 }
369 this.write_scalar(Scalar::from_i32(1), dest)?;
370 }
371 "HeapReAlloc" => {
372 let [handle, flags, old_ptr, size] =
373 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
374 this.read_target_isize(handle)?;
375 this.read_scalar(flags)?.to_u32()?;
376 let old_ptr = this.read_pointer(old_ptr)?;
377 let size = this.read_target_usize(size)?;
378 let align = this.tcx.pointer_size().bytes().strict_mul(2); let new_ptr = this.reallocate_ptr(
383 old_ptr,
384 None,
385 Size::from_bytes(size),
386 Align::from_bytes(align).unwrap(),
387 MiriMemoryKind::WinHeap.into(),
388 AllocInit::Uninit,
389 )?;
390 this.write_pointer(new_ptr, dest)?;
391 }
392 "LocalFree" => {
393 let [ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
394 let ptr = this.read_pointer(ptr)?;
395 if !this.ptr_is_null(ptr)? {
398 this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
399 }
400 this.write_null(dest)?;
401 }
402
403 "SetLastError" => {
405 let [error] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
406 let error = this.read_scalar(error)?;
407 this.set_last_error(error)?;
408 }
409 "GetLastError" => {
410 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
411 let last_error = this.get_last_error()?;
412 this.write_scalar(last_error, dest)?;
413 }
414 "RtlNtStatusToDosError" => {
415 let [status] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
416 let status = this.read_scalar(status)?.to_u32()?;
417 let err = match status {
418 0xC00000A2 => 19,
420 0xC0000098 => 1006,
422 0xC000007F => 112,
424 0xC0000185 => 1117,
426 0xC0000022 => 5,
428 _ => 317,
430 };
431 this.write_scalar(Scalar::from_i32(err), dest)?;
432 }
433
434 "GetSystemInfo" => {
436 let [system_info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
438 let system_info =
439 this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
440 this.write_bytes_ptr(
442 system_info.ptr(),
443 iter::repeat_n(0u8, system_info.layout.size.bytes_usize()),
444 )?;
445 this.write_int_fields_named(
447 &[
448 ("dwPageSize", this.machine.page_size.into()),
449 ("dwNumberOfProcessors", this.machine.num_cpus.into()),
450 ],
451 &system_info,
452 )?;
453 }
454
455 "TlsAlloc" => {
457 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
461 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
462 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
463 }
464 "TlsGetValue" => {
465 let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
466 let key = u128::from(this.read_scalar(key)?.to_u32()?);
467 let active_thread = this.active_thread();
468 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
469 this.write_scalar(ptr, dest)?;
470 }
471 "TlsSetValue" => {
472 let [key, new_ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
473 let key = u128::from(this.read_scalar(key)?.to_u32()?);
474 let active_thread = this.active_thread();
475 let new_data = this.read_scalar(new_ptr)?;
476 this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
477
478 this.write_int(1, dest)?;
480 }
481 "TlsFree" => {
482 let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
483 let key = u128::from(this.read_scalar(key)?.to_u32()?);
484 this.machine.tls.delete_tls_key(key)?;
485
486 this.write_int(1, dest)?;
488 }
489
490 "GetCommandLineW" => {
492 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
493 this.write_pointer(
494 this.machine.cmd_line.expect("machine must be initialized"),
495 dest,
496 )?;
497 }
498
499 "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
501 #[allow(non_snake_case)]
502 let [LPFILETIME] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
503 this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
504 }
505 "QueryPerformanceCounter" => {
506 #[allow(non_snake_case)]
507 let [lpPerformanceCount] =
508 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
509 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
510 this.write_scalar(result, dest)?;
511 }
512 "QueryPerformanceFrequency" => {
513 #[allow(non_snake_case)]
514 let [lpFrequency] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
515 let result = this.QueryPerformanceFrequency(lpFrequency)?;
516 this.write_scalar(result, dest)?;
517 }
518 "Sleep" => {
519 let [timeout] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
520
521 this.Sleep(timeout)?;
522 }
523 "CreateWaitableTimerExW" => {
524 let [attributes, name, flags, access] =
525 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
526 this.read_pointer(attributes)?;
527 this.read_pointer(name)?;
528 this.read_scalar(flags)?.to_u32()?;
529 this.read_scalar(access)?.to_u32()?;
530 let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
532 this.set_last_error(not_supported)?;
533 this.write_null(dest)?;
534 }
535
536 "InitOnceBeginInitialize" => {
538 let [ptr, flags, pending, context] =
539 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
540 this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
541 }
542 "InitOnceComplete" => {
543 let [ptr, flags, context] =
544 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
545 let result = this.InitOnceComplete(ptr, flags, context)?;
546 this.write_scalar(result, dest)?;
547 }
548 "WaitOnAddress" => {
549 let [ptr_op, compare_op, size_op, timeout_op] =
550 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
551
552 this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
553 }
554 "WakeByAddressSingle" => {
555 let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
556
557 this.WakeByAddressSingle(ptr_op)?;
558 }
559 "WakeByAddressAll" => {
560 let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
561
562 this.WakeByAddressAll(ptr_op)?;
563 }
564
565 "GetProcAddress" => {
567 #[allow(non_snake_case)]
568 let [hModule, lpProcName] =
569 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
570 this.read_target_isize(hModule)?;
571 let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
572 if let Ok(name) = str::from_utf8(name)
573 && is_dyn_sym(name)
574 {
575 let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
576 this.write_pointer(ptr, dest)?;
577 } else {
578 this.write_null(dest)?;
579 }
580 }
581
582 "CreateThread" => {
584 let [security, stacksize, start, arg, flags, thread] =
585 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
586
587 let thread_id =
588 this.CreateThread(security, stacksize, start, arg, flags, thread)?;
589
590 this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
591 }
592 "WaitForSingleObject" => {
593 let [handle, timeout] =
594 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
595
596 this.WaitForSingleObject(handle, timeout, dest)?;
597 }
598 "GetCurrentProcess" => {
599 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
600
601 this.write_scalar(
602 Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
603 dest,
604 )?;
605 }
606 "GetCurrentThread" => {
607 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
608
609 this.write_scalar(
610 Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
611 dest,
612 )?;
613 }
614 "SetThreadDescription" => {
615 let [handle, name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
616
617 let handle = this.read_handle(handle, "SetThreadDescription")?;
618 let name = this.read_wide_str(this.read_pointer(name)?)?;
619
620 let thread = match handle {
621 Handle::Thread(thread) => thread,
622 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
623 _ => this.invalid_handle("SetThreadDescription")?,
624 };
625 this.set_thread_name(thread, String::from_utf16_lossy(&name).into_bytes());
627 this.write_scalar(Scalar::from_u32(0), dest)?;
628 }
629 "GetThreadDescription" => {
630 let [handle, name_ptr] =
631 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
632
633 let handle = this.read_handle(handle, "GetThreadDescription")?;
634 let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; let thread = match handle {
637 Handle::Thread(thread) => thread,
638 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
639 _ => this.invalid_handle("GetThreadDescription")?,
640 };
641 let name = this.get_thread_name(thread).unwrap_or(b"").to_owned();
643 let name = this.alloc_os_str_as_wide_str(
644 bytes_to_os_str(&name)?,
645 MiriMemoryKind::WinLocal.into(),
646 )?;
647 let name = Scalar::from_maybe_pointer(name, this);
648 let res = Scalar::from_u32(0);
649
650 this.write_scalar(name, &name_ptr)?;
651 this.write_scalar(res, dest)?;
652 }
653 "GetThreadId" => {
654 let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
655 let handle = this.read_handle(handle, "GetThreadId")?;
656 let thread = match handle {
657 Handle::Thread(thread) => thread,
658 Handle::Pseudo(PseudoHandle::CurrentThread) => this.active_thread(),
659 _ => this.invalid_handle("GetThreadDescription")?,
660 };
661 let tid = this.get_tid(thread);
662 this.write_scalar(Scalar::from_u32(tid), dest)?;
663 }
664 "GetCurrentThreadId" => {
665 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
666 let thread = this.active_thread();
667 let tid = this.get_tid(thread);
668 this.write_scalar(Scalar::from_u32(tid), dest)?;
669 }
670
671 "ExitProcess" => {
673 let [code] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
674 let code = this.read_scalar(code)?.to_i32()?;
676 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
677 }
678 "SystemFunction036" => {
679 let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
682 let ptr = this.read_pointer(ptr)?;
683 let len = this.read_scalar(len)?.to_u32()?;
684 this.gen_random(ptr, len.into())?;
685 this.write_scalar(Scalar::from_bool(true), dest)?;
686 }
687 "ProcessPrng" => {
688 let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
690 let ptr = this.read_pointer(ptr)?;
691 let len = this.read_target_usize(len)?;
692 this.gen_random(ptr, len)?;
693 this.write_int(1, dest)?;
694 }
695 "BCryptGenRandom" => {
696 let [algorithm, ptr, len, flags] =
698 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
699 let algorithm = this.read_scalar(algorithm)?;
700 let algorithm = algorithm.to_target_usize(this)?;
701 let ptr = this.read_pointer(ptr)?;
702 let len = this.read_scalar(len)?.to_u32()?;
703 let flags = this.read_scalar(flags)?.to_u32()?;
704 match flags {
705 0 => {
706 if algorithm != 0x81 {
707 throw_unsup_format!(
709 "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0"
710 );
711 }
712 }
713 2 => {
714 if algorithm != 0 {
716 throw_unsup_format!(
717 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
718 );
719 }
720 }
721 _ => {
722 throw_unsup_format!(
723 "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE"
724 );
725 }
726 }
727 this.gen_random(ptr, len.into())?;
728 this.write_null(dest)?; }
730 "GetConsoleScreenBufferInfo" => {
731 let [console, buffer_info] =
733 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
734 this.read_target_isize(console)?;
735 this.deref_pointer(buffer_info)?;
737 this.write_null(dest)?;
740 }
741 "GetStdHandle" => {
742 let [which] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
743 let res = this.GetStdHandle(which)?;
744 this.write_scalar(res, dest)?;
745 }
746 "DuplicateHandle" => {
747 let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
748 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
749 let res = this.DuplicateHandle(
750 src_proc,
751 src_handle,
752 target_proc,
753 target_handle,
754 access,
755 inherit,
756 options,
757 )?;
758 this.write_scalar(res, dest)?;
759 }
760 "CloseHandle" => {
761 let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
762
763 let ret = this.CloseHandle(handle)?;
764
765 this.write_scalar(ret, dest)?;
766 }
767 "GetModuleFileNameW" => {
768 let [handle, filename, size] =
769 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
770 this.check_no_isolation("`GetModuleFileNameW`")?;
771
772 let handle = this.read_handle(handle, "GetModuleFileNameW")?;
773 let filename = this.read_pointer(filename)?;
774 let size = this.read_scalar(size)?.to_u32()?;
775
776 if handle != Handle::Null {
777 throw_unsup_format!("`GetModuleFileNameW` only supports the NULL handle");
778 }
779
780 let path = std::env::current_exe().unwrap();
783 let (all_written, size_needed) =
784 this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
785
786 if all_written {
787 this.write_int(size_needed.strict_sub(1), dest)?;
791 } else {
792 this.write_int(size, dest)?;
797 let insufficient_buffer = this.eval_windows("c", "ERROR_INSUFFICIENT_BUFFER");
798 this.set_last_error(insufficient_buffer)?;
799 }
800 }
801 "FormatMessageW" => {
802 let [flags, module, message_id, language_id, buffer, size, arguments] =
803 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
804
805 let flags = this.read_scalar(flags)?.to_u32()?;
806 let _module = this.read_pointer(module)?; let message_id = this.read_scalar(message_id)?;
808 let _language_id = this.read_scalar(language_id)?.to_u32()?;
809 let buffer = this.read_pointer(buffer)?;
810 let size = this.read_scalar(size)?.to_u32()?;
811 let _arguments = this.read_pointer(arguments)?;
812
813 if flags != 4096u32 | 512u32 {
816 throw_unsup_format!("FormatMessageW: unsupported flags {flags:#x}");
817 }
818
819 let error = this.try_errnum_to_io_error(message_id)?;
820 let formatted = match error {
821 Some(err) => format!("{err}"),
822 None => format!("<unknown error in FormatMessageW: {message_id}>"),
823 };
824 let (complete, length) =
825 this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
826 if !complete {
827 throw_unsup_format!("FormatMessageW: buffer not big enough");
830 }
831 this.write_int(length.strict_sub(1), dest)?;
833 }
834
835 "_Unwind_RaiseException" => {
836 if this.tcx.sess.target.env != Env::Gnu {
841 throw_unsup_format!(
842 "`_Unwind_RaiseException` is not supported on non-MinGW Windows",
843 );
844 }
845 let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
847 this.handle_miri_start_unwind(payload)?;
848 return interp_ok(EmulateItemResult::NeedsUnwind);
849 }
850
851 "GetProcessHeap" if this.frame_in_std() => {
854 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
855 this.write_int(1, dest)?;
858 }
859 "GetModuleHandleA" if this.frame_in_std() => {
860 #[allow(non_snake_case)]
861 let [_lpModuleName] =
862 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
863 this.write_int(1, dest)?;
865 }
866 "SetConsoleTextAttribute" if this.frame_in_std() => {
867 #[allow(non_snake_case)]
868 let [_hConsoleOutput, _wAttribute] =
869 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
870 this.write_null(dest)?;
872 }
873 "GetConsoleMode" if this.frame_in_std() => {
874 let [console, mode] =
875 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
876 this.read_target_isize(console)?;
877 this.deref_pointer_as(mode, this.machine.layouts.u32)?;
878 this.write_null(dest)?;
880 }
881 "GetFileType" if this.frame_in_std() => {
882 #[allow(non_snake_case)]
883 let [_hFile] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
884 this.write_null(dest)?;
886 }
887 "AddVectoredExceptionHandler" if this.frame_in_std() => {
888 #[allow(non_snake_case)]
889 let [_First, _Handler] =
890 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
891 this.write_int(1, dest)?;
893 }
894 "SetThreadStackGuarantee" if this.frame_in_std() => {
895 #[allow(non_snake_case)]
896 let [_StackSizeInBytes] =
897 this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
898 this.write_int(1, dest)?;
900 }
901 "SwitchToThread" if this.frame_in_std() => {
903 let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
904
905 this.yield_active_thread();
906
907 this.write_null(dest)?;
909 }
910
911 _ => return interp_ok(EmulateItemResult::NotSupported),
912 }
913
914 interp_ok(EmulateItemResult::NeedsReturn)
915 }
916}