diff --git a/src/shims/sig.rs b/src/shims/sig.rs index bc5e7f584f..7704795d20 100644 --- a/src/shims/sig.rs +++ b/src/shims/sig.rs @@ -17,11 +17,11 @@ 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) /// ``` #[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 +53,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::>()).ty, } }}; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 3bc52dddfe..3260768e0a 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -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; @@ -141,61 +141,100 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 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 - }; + // TODO: Use this in shim-sig instead of 'system'? Or is that good enough for ExternAbi? + // 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 + // 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 +251,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 +293,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 +325,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 +367,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 +395,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 +456,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 +483,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 +500,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 +525,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 +542,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 +589,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 +617,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 +654,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 +669,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 +683,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 +740,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 +812,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 +834,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 +857,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 +870,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 +890,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 +918,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 +934,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 +947,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 +960,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 +974,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 +987,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 +1026,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 +1040,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 +1079,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 +1129,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 +1180,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 +1193,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(); diff --git a/tests/pass-dep/getrandom.rs b/tests/pass-dep/getrandom.rs index d359730e7f..744ba64996 100644 --- a/tests/pass-dep/getrandom.rs +++ b/tests/pass-dep/getrandom.rs @@ -12,6 +12,8 @@ fn main() { #[cfg(not(target_os = "solaris"))] getrandom_01::getrandom(&mut data).unwrap(); + // TODO: getrandom 0.2 uses the wrong return type for BCrypteGenRandom + #[cfg(not(target_os = "windows"))] getrandom_02::getrandom(&mut data).unwrap(); getrandom_03::fill(&mut data).unwrap(); diff --git a/tests/pass/tls/windows-tls.rs b/tests/pass/tls/windows-tls.rs index 58131be190..9c5e8eea4d 100644 --- a/tests/pass/tls/windows-tls.rs +++ b/tests/pass/tls/windows-tls.rs @@ -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 }); }