Convert Windows to use check_shim_sig instead of check_shim_sig_lenient

This commit is contained in:
Rune Tynan 2025-12-19 10:27:38 -08:00 committed by Ralf Jung
parent ff2acf0eca
commit c5f67830c2
4 changed files with 497 additions and 129 deletions

View file

@ -17,11 +17,14 @@ pub struct ShimSig<'tcx, const ARGS: usize> {
/// Construct a `ShimSig` with convenient syntax:
/// ```rust,ignore
/// shim_sig!(this, extern "C" fn (*const T, i32) -> usize)
/// shim_sig!(extern "C" fn (*const T, i32) -> usize)
/// ```
///
/// In type position, `winapi::` can be used as a shorthand for the full path used by
/// `windows_ty_layout`.
#[macro_export]
macro_rules! shim_sig {
(extern $abi:literal fn($($arg:ty),*) -> $ret:ty) => {
(extern $abi:literal fn($($arg:ty),* $(,)?) -> $ret:ty) => {
|this| $crate::shims::sig::ShimSig {
abi: std::str::FromStr::from_str($abi).expect("incorrect abi specified"),
args: [$(shim_sig_arg!(this, $arg)),*],
@ -53,7 +56,9 @@ macro_rules! shim_sig_arg {
"*const _" => $this.machine.layouts.const_raw_ptr.ty,
"*mut _" => $this.machine.layouts.mut_raw_ptr.ty,
ty if let Some(libc_ty) = ty.strip_prefix("libc::") => $this.libc_ty_layout(libc_ty).ty,
ty => panic!("unsupported signature type {ty:?}"),
ty if let Some(win_ty) = ty.strip_prefix("winapi::") =>
$this.windows_ty_layout(win_ty).ty,
ty => helpers::path_ty_layout($this, &ty.split("::").collect::<Vec<_>>()).ty,
}
}};
}

View file

@ -2,11 +2,11 @@ use std::ffi::OsStr;
use std::path::{self, Path, PathBuf};
use std::{io, iter, str};
use rustc_abi::{Align, CanonAbi, Size, X86Call};
use rustc_abi::{Align, Size};
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::FnAbi;
use rustc_target::spec::{Arch, Env};
use rustc_target::spec::Env;
use self::shims::windows::handle::{Handle, PseudoHandle};
use crate::shims::os_str::bytes_to_os_str;
@ -137,65 +137,93 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut();
// According to
// https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768,
// x86-32 Windows uses a different calling convention than other Windows targets
// for the "system" ABI.
let sys_conv = if this.tcx.sess.target.arch == Arch::X86 {
CanonAbi::X86(X86Call::Stdcall)
} else {
CanonAbi::C
};
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
// Windows API stubs.
// HANDLE = isize
// NTSTATUS = LONH = i32
// HANDLE = *mut c_void (formerly: isize)
// NTSTATUS = LONG = i32
// DWORD = ULONG = u32
// BOOL = i32
// BOOLEAN = u8
match link_name.as_str() {
// Environment related shims
"GetEnvironmentVariableW" => {
let [name, buf, size] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [name, buf, size] = this.check_shim_sig(
shim_sig!(extern "system" fn(*const _, *mut _, u32) -> u32),
link_name,
abi,
args,
)?;
let result = this.GetEnvironmentVariableW(name, buf, size)?;
this.write_scalar(result, dest)?;
}
"SetEnvironmentVariableW" => {
let [name, value] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [name, value] = this.check_shim_sig(
shim_sig!(extern "system" fn(*const _, *const _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let result = this.SetEnvironmentVariableW(name, value)?;
this.write_scalar(result, dest)?;
}
"GetEnvironmentStringsW" => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> *mut _),
link_name,
abi,
args,
)?;
let result = this.GetEnvironmentStringsW()?;
this.write_pointer(result, dest)?;
}
"FreeEnvironmentStringsW" => {
let [env_block] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [env_block] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let result = this.FreeEnvironmentStringsW(env_block)?;
this.write_scalar(result, dest)?;
}
"GetCurrentDirectoryW" => {
let [size, buf] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [size, buf] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32, *mut _) -> u32),
link_name,
abi,
args,
)?;
let result = this.GetCurrentDirectoryW(size, buf)?;
this.write_scalar(result, dest)?;
}
"SetCurrentDirectoryW" => {
let [path] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [path] = this.check_shim_sig(
shim_sig!(extern "system" fn(*const _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let result = this.SetCurrentDirectoryW(path)?;
this.write_scalar(result, dest)?;
}
"GetUserProfileDirectoryW" => {
let [token, buf, size] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [token, buf, size] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, *mut _, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let result = this.GetUserProfileDirectoryW(token, buf, size)?;
this.write_scalar(result, dest)?;
}
"GetCurrentProcessId" => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> u32),
link_name,
abi,
args,
)?;
let result = this.GetCurrentProcessId()?;
this.write_scalar(result, dest)?;
}
@ -212,7 +240,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
n,
byte_offset,
key,
] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
] = this.check_shim_sig(
shim_sig!(
extern "system" fn(
winapi::HANDLE,
winapi::HANDLE,
*mut _,
*mut _,
*mut _,
*mut _,
u32,
*mut _,
*mut _,
) -> i32
),
link_name,
abi,
args,
)?;
this.NtWriteFile(
handle,
event,
@ -237,7 +282,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
n,
byte_offset,
key,
] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
] = this.check_shim_sig(
shim_sig!(
extern "system" fn(
winapi::HANDLE,
winapi::HANDLE,
*mut _,
*mut _,
*mut _,
*mut _,
u32,
*mut _,
*mut _,
) -> i32
),
link_name,
abi,
args,
)?;
this.NtReadFile(
handle,
event,
@ -252,8 +314,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
}
"GetFullPathNameW" => {
let [filename, size, buffer, filepart] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [filename, size, buffer, filepart] = this.check_shim_sig(
shim_sig!(extern "system" fn(*const _, u32, *mut _, *mut _) -> u32),
link_name,
abi,
args,
)?;
this.check_no_isolation("`GetFullPathNameW`")?;
let filename = this.read_pointer(filename)?;
@ -290,7 +356,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
creation_disposition,
flags_and_attributes,
template_file,
] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
] = this.check_shim_sig(
shim_sig!(
extern "system" fn(
*const _,
u32,
u32,
*mut _,
u32,
u32,
winapi::HANDLE,
) -> winapi::HANDLE
),
link_name,
abi,
args,
)?;
let handle = this.CreateFileW(
file_name,
desired_access,
@ -303,29 +384,60 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(handle.to_scalar(this), dest)?;
}
"GetFileInformationByHandle" => {
let [handle, info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, info] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let res = this.GetFileInformationByHandle(handle, info)?;
this.write_scalar(res, dest)?;
}
"SetFileInformationByHandle" => {
let [handle, class, info, size] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, class, info, size] = this.check_shim_sig(
shim_sig!(
extern "system" fn(
winapi::HANDLE,
winapi::FILE_INFO_BY_HANDLE_CLASS,
*mut _,
u32,
) -> winapi::BOOL
),
link_name,
abi,
args,
)?;
let res = this.SetFileInformationByHandle(handle, class, info, size)?;
this.write_scalar(res, dest)?;
}
"FlushFileBuffers" => {
let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let res = this.FlushFileBuffers(handle)?;
this.write_scalar(res, dest)?;
}
"DeleteFileW" => {
let [file_name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [file_name] = this.check_shim_sig(
shim_sig!(extern "system" fn(*const _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let res = this.DeleteFileW(file_name)?;
this.write_scalar(res, dest)?;
}
"SetFilePointerEx" => {
let [file, distance_to_move, new_file_pointer, move_method] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [file, distance_to_move, new_file_pointer, move_method] = this.check_shim_sig(
// i64 is actually a LARGE_INTEGER union of {u32, i32} and {i64}
shim_sig!(extern "system" fn(winapi::HANDLE, i64, *mut _, u32) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let res =
this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
this.write_scalar(res, dest)?;
@ -333,8 +445,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Allocation
"HeapAlloc" => {
let [handle, flags, size] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, flags, size] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *mut _),
link_name,
abi,
args,
)?;
this.read_target_isize(handle)?;
let flags = this.read_scalar(flags)?.to_u32()?;
let size = this.read_target_usize(size)?;
@ -356,8 +472,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_pointer(ptr, dest)?;
}
"HeapFree" => {
let [handle, flags, ptr] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, flags, ptr] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
this.read_target_isize(handle)?;
this.read_scalar(flags)?.to_u32()?;
let ptr = this.read_pointer(ptr)?;
@ -369,8 +489,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(Scalar::from_i32(1), dest)?;
}
"HeapReAlloc" => {
let [handle, flags, old_ptr, size] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, flags, old_ptr, size] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _, usize) -> *mut _),
link_name,
abi,
args,
)?;
this.read_target_isize(handle)?;
this.read_scalar(flags)?.to_u32()?;
let old_ptr = this.read_pointer(old_ptr)?;
@ -390,7 +514,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_pointer(new_ptr, dest)?;
}
"LocalFree" => {
let [ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HLOCAL) -> winapi::HLOCAL),
link_name,
abi,
args,
)?;
let ptr = this.read_pointer(ptr)?;
// "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL."
// (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree)
@ -402,17 +531,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// errno
"SetLastError" => {
let [error] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [error] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32) -> ()),
link_name,
abi,
args,
)?;
let error = this.read_scalar(error)?;
this.set_last_error(error)?;
}
"GetLastError" => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> u32),
link_name,
abi,
args,
)?;
let last_error = this.get_last_error()?;
this.write_scalar(last_error, dest)?;
}
"RtlNtStatusToDosError" => {
let [status] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [status] = this.check_shim_sig(
shim_sig!(extern "system" fn(i32) -> u32),
link_name,
abi,
args,
)?;
let status = this.read_scalar(status)?.to_u32()?;
let err = match status {
// STATUS_MEDIA_WRITE_PROTECTED => ERROR_WRITE_PROTECT
@ -434,7 +578,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Querying system information
"GetSystemInfo" => {
// Also called from `page_size` crate.
let [system_info] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [system_info] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> ()),
link_name,
abi,
args,
)?;
let system_info =
this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
// Initialize with `0`.
@ -457,19 +606,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// This just creates a key; Windows does not natively support TLS destructors.
// Create key and return it.
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> u32),
link_name,
abi,
args,
)?;
let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
}
"TlsGetValue" => {
let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [key] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32) -> *mut _),
link_name,
abi,
args,
)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
let active_thread = this.active_thread();
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
this.write_scalar(ptr, dest)?;
}
"TlsSetValue" => {
let [key, new_ptr] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [key, new_ptr] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
let active_thread = this.active_thread();
let new_data = this.read_scalar(new_ptr)?;
@ -479,7 +643,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_int(1, dest)?;
}
"TlsFree" => {
let [key] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [key] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
this.machine.tls.delete_tls_key(key)?;
@ -489,7 +658,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Access to command-line arguments
"GetCommandLineW" => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> *mut _),
link_name,
abi,
args,
)?;
this.write_pointer(
this.machine.cmd_line.expect("machine must be initialized"),
dest,
@ -498,31 +672,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Time related shims
"GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
#[allow(non_snake_case)]
let [LPFILETIME] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
let [filetime] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> ()),
link_name,
abi,
args,
)?;
this.GetSystemTimeAsFileTime(link_name.as_str(), filetime)?;
}
"QueryPerformanceCounter" => {
#[allow(non_snake_case)]
let [lpPerformanceCount] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
let [performance_count] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let result = this.QueryPerformanceCounter(performance_count)?;
this.write_scalar(result, dest)?;
}
"QueryPerformanceFrequency" => {
#[allow(non_snake_case)]
let [lpFrequency] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let result = this.QueryPerformanceFrequency(lpFrequency)?;
let [frequency] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let result = this.QueryPerformanceFrequency(frequency)?;
this.write_scalar(result, dest)?;
}
"Sleep" => {
let [timeout] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [timeout] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32) -> ()),
link_name,
abi,
args,
)?;
this.Sleep(timeout)?;
}
"CreateWaitableTimerExW" => {
let [attributes, name, flags, access] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [attributes, name, flags, access] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE),
link_name,
abi,
args,
)?;
this.read_pointer(attributes)?;
this.read_pointer(name)?;
this.read_scalar(flags)?.to_u32()?;
@ -535,40 +729,66 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Synchronization primitives
"InitOnceBeginInitialize" => {
let [ptr, flags, pending, context] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr, flags, pending, context] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _, u32, *mut _, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
}
"InitOnceComplete" => {
let [ptr, flags, context] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr, flags, context] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _, u32, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let result = this.InitOnceComplete(ptr, flags, context)?;
this.write_scalar(result, dest)?;
}
"WaitOnAddress" => {
let [ptr_op, compare_op, size_op, timeout_op] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig(
// First pointer is volatile
shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL),
link_name,
abi,
args,
)?;
this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
}
"WakeByAddressSingle" => {
let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr_op] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> ()),
link_name,
abi,
args,
)?;
this.WakeByAddressSingle(ptr_op)?;
}
"WakeByAddressAll" => {
let [ptr_op] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr_op] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> ()),
link_name,
abi,
args,
)?;
this.WakeByAddressAll(ptr_op)?;
}
// Dynamic symbol loading
"GetProcAddress" => {
#[allow(non_snake_case)]
let [hModule, lpProcName] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.read_target_isize(hModule)?;
let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
let [module, proc_name] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC),
link_name,
abi,
args,
)?;
this.read_target_isize(module)?;
let name = this.read_c_str(this.read_pointer(proc_name)?)?;
if let Ok(name) = str::from_utf8(name)
&& is_dyn_sym(name)
{
@ -581,8 +801,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Threading
"CreateThread" => {
let [security, stacksize, start, arg, flags, thread] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig(
shim_sig!(
extern "system" fn(
*mut _,
usize,
*mut _,
*mut _,
u32,
*mut _,
) -> winapi::HANDLE
),
link_name,
abi,
args,
)?;
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;
@ -590,13 +823,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, timeout] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, u32) -> u32),
link_name,
abi,
args,
)?;
this.WaitForSingleObject(handle, timeout, dest)?;
}
"GetCurrentProcess" => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> winapi::HANDLE),
link_name,
abi,
args,
)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
@ -604,7 +846,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
}
"GetCurrentThread" => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> winapi::HANDLE),
link_name,
abi,
args,
)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
@ -612,7 +859,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
}
"SetThreadDescription" => {
let [handle, name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, name] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, *const _) -> i32),
link_name,
abi,
args,
)?;
let handle = this.read_handle(handle, "SetThreadDescription")?;
let name = this.read_wide_str(this.read_pointer(name)?)?;
@ -627,8 +879,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(Scalar::from_u32(0), dest)?;
}
"GetThreadDescription" => {
let [handle, name_ptr] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, name_ptr] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> i32),
link_name,
abi,
args,
)?;
let handle = this.read_handle(handle, "GetThreadDescription")?;
let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name
@ -651,7 +907,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"GetThreadId" => {
let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
link_name,
abi,
args,
)?;
let handle = this.read_handle(handle, "GetThreadId")?;
let thread = match handle {
Handle::Thread(thread) => thread,
@ -662,7 +923,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(Scalar::from_u32(tid), dest)?;
}
"GetCurrentThreadId" => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> u32),
link_name,
abi,
args,
)?;
let thread = this.active_thread();
let tid = this.get_tid(thread);
this.write_scalar(Scalar::from_u32(tid), dest)?;
@ -670,7 +936,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Miscellaneous
"ExitProcess" => {
let [code] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [code] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32) -> ()),
link_name,
abi,
args,
)?;
// Windows technically uses u32, but we unify everything to a Unix-style i32.
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
@ -678,7 +949,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"SystemFunction036" => {
// used by getrandom 0.1
// This is really 'RtlGenRandom'.
let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr, len] = this.check_shim_sig(
// Returns winapi::BOOLEAN, which is a byte
shim_sig!(extern "system" fn(*mut _, u32) -> u8),
link_name,
abi,
args,
)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_scalar(len)?.to_u32()?;
this.gen_random(ptr, len.into())?;
@ -686,7 +963,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"ProcessPrng" => {
// used by `std`
let [ptr, len] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [ptr, len] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
this.gen_random(ptr, len)?;
@ -694,8 +976,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"BCryptGenRandom" => {
// used by getrandom 0.2
let [algorithm, ptr, len, flags] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [algorithm, ptr, len, flags] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _, *mut _, u32, u32) -> i32),
link_name,
abi,
args,
)?;
let algorithm = this.read_scalar(algorithm)?;
let algorithm = algorithm.to_target_usize(this)?;
let ptr = this.read_pointer(ptr)?;
@ -729,8 +1015,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"GetConsoleScreenBufferInfo" => {
// `term` needs this, so we fake it.
let [console, buffer_info] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [console, buffer_info] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
this.read_target_isize(console)?;
// FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
this.deref_pointer(buffer_info)?;
@ -739,13 +1029,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_null(dest)?;
}
"GetStdHandle" => {
let [which] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [which] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32) -> winapi::HANDLE),
link_name,
abi,
args,
)?;
let res = this.GetStdHandle(which)?;
this.write_scalar(res, dest)?;
}
"DuplicateHandle" => {
let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
this.check_shim_sig(
shim_sig!(
extern "system" fn(
winapi::HANDLE,
winapi::HANDLE,
winapi::HANDLE,
*mut _,
u32,
winapi::BOOL,
u32,
) -> winapi::BOOL
),
link_name,
abi,
args,
)?;
let res = this.DuplicateHandle(
src_proc,
src_handle,
@ -758,15 +1068,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"CloseHandle" => {
let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE) -> winapi::BOOL),
link_name,
abi,
args,
)?;
let ret = this.CloseHandle(handle)?;
this.write_scalar(ret, dest)?;
}
"GetModuleFileNameW" => {
let [handle, filename, size] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [handle, filename, size] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32),
link_name,
abi,
args,
)?;
this.check_no_isolation("`GetModuleFileNameW`")?;
let handle = this.read_handle(handle, "GetModuleFileNameW")?;
@ -799,8 +1118,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
"FormatMessageW" => {
let [flags, module, message_id, language_id, buffer, size, arguments] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [flags, module, message_id, language_id, buffer, size, arguments] = this
.check_shim_sig(
shim_sig!(
extern "system" fn(u32, *const _, u32, u32, *mut _, u32, *mut _) -> u32
),
link_name,
abi,
args,
)?;
let flags = this.read_scalar(flags)?.to_u32()?;
let _module = this.read_pointer(module)?; // seems to contain a module name
@ -843,7 +1169,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
);
}
// This function looks and behaves excatly like miri_start_unwind.
let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let [payload] = this.check_shim_sig(
shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code),
link_name,
abi,
args,
)?;
this.handle_miri_start_unwind(payload)?;
return interp_ok(EmulateItemResult::NeedsUnwind);
}
@ -851,56 +1182,86 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
"GetProcessHeap" if this.frame_in_std() => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> winapi::HANDLE),
link_name,
abi,
args,
)?;
// Just fake a HANDLE
// It's fine to not use the Handle type here because its a stub
this.write_int(1, dest)?;
}
"GetModuleHandleA" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_lpModuleName] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [_module_name] = this.check_shim_sig(
shim_sig!(extern "system" fn(*const _) -> winapi::HMODULE),
link_name,
abi,
args,
)?;
// We need to return something non-null here to make `compat_fn!` work.
this.write_int(1, dest)?;
}
"SetConsoleTextAttribute" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_hConsoleOutput, _wAttribute] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [_console_output, _attribute] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, u16) -> winapi::BOOL),
link_name,
abi,
args,
)?;
// Pretend these does not exist / nothing happened, by returning zero.
this.write_null(dest)?;
}
"GetConsoleMode" if this.frame_in_std() => {
let [console, mode] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [console, mode] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
this.read_target_isize(console)?;
this.deref_pointer_as(mode, this.machine.layouts.u32)?;
// Indicate an error.
this.write_null(dest)?;
}
"GetFileType" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_hFile] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [_file] = this.check_shim_sig(
shim_sig!(extern "system" fn(winapi::HANDLE) -> u32),
link_name,
abi,
args,
)?;
// Return unknown file type.
this.write_null(dest)?;
}
"AddVectoredExceptionHandler" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_First, _Handler] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [_first, _handler] = this.check_shim_sig(
shim_sig!(extern "system" fn(u32, *mut _) -> *mut _),
link_name,
abi,
args,
)?;
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_int(1, dest)?;
}
"SetThreadStackGuarantee" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_StackSizeInBytes] =
this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [_stack_size_in_bytes] = this.check_shim_sig(
shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL),
link_name,
abi,
args,
)?;
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_int(1, dest)?;
}
// this is only callable from std because we know that std ignores the return value
"SwitchToThread" if this.frame_in_std() => {
let [] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?;
let [] = this.check_shim_sig(
shim_sig!(extern "system" fn() -> winapi::BOOL),
link_name,
abi,
args,
)?;
this.yield_active_thread();

View file

@ -12,6 +12,8 @@ fn main() {
#[cfg(not(target_os = "solaris"))]
getrandom_01::getrandom(&mut data).unwrap();
// On Windows, getrandom 0.2 uses the wrong return type for BCryptGenRandom
#[cfg(not(target_os = "windows"))]
getrandom_02::getrandom(&mut data).unwrap();
getrandom_03::fill(&mut data).unwrap();

View file

@ -5,14 +5,14 @@ use std::ptr;
extern "system" {
fn TlsAlloc() -> u32;
fn TlsSetValue(key: u32, val: *mut c_void) -> bool;
fn TlsSetValue(key: u32, val: *mut c_void) -> i32;
fn TlsGetValue(key: u32) -> *mut c_void;
fn TlsFree(key: u32) -> bool;
fn TlsFree(key: u32) -> i32;
}
fn main() {
let key = unsafe { TlsAlloc() };
assert!(unsafe { TlsSetValue(key, ptr::without_provenance_mut(1)) });
assert!(unsafe { TlsSetValue(key, ptr::without_provenance_mut(1)) != 0 });
assert_eq!(unsafe { TlsGetValue(key).addr() }, 1);
assert!(unsafe { TlsFree(key) });
assert!(unsafe { TlsFree(key) != 0 });
}