4 use rustc_target::abi::Size;
7 use helpers::check_arg_count;
8 use shims::windows::sync::EvalContextExt as _;
10 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
11 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
12 fn emulate_foreign_item_by_name(
15 args: &[OpTy<'tcx, Tag>],
16 dest: PlaceTy<'tcx, Tag>,
17 _ret: mir::BasicBlock,
18 ) -> InterpResult<'tcx, bool> {
19 let this = self.eval_context_mut();
23 // DWORD = ULONG = u32
27 // Environment related shims
28 "GetEnvironmentVariableW" => {
29 let &[name, buf, size] = check_arg_count(args)?;
30 let result = this.GetEnvironmentVariableW(name, buf, size)?;
31 this.write_scalar(Scalar::from_u32(result), dest)?;
33 "SetEnvironmentVariableW" => {
34 let &[name, value] = check_arg_count(args)?;
35 let result = this.SetEnvironmentVariableW(name, value)?;
36 this.write_scalar(Scalar::from_i32(result), dest)?;
38 "GetEnvironmentStringsW" => {
39 let &[] = check_arg_count(args)?;
40 let result = this.GetEnvironmentStringsW()?;
41 this.write_scalar(result, dest)?;
43 "FreeEnvironmentStringsW" => {
44 let &[env_block] = check_arg_count(args)?;
45 let result = this.FreeEnvironmentStringsW(env_block)?;
46 this.write_scalar(Scalar::from_i32(result), dest)?;
48 "GetCurrentDirectoryW" => {
49 let &[size, buf] = check_arg_count(args)?;
50 let result = this.GetCurrentDirectoryW(size, buf)?;
51 this.write_scalar(Scalar::from_u32(result), dest)?;
53 "SetCurrentDirectoryW" => {
54 let &[path] = check_arg_count(args)?;
55 let result = this.SetCurrentDirectoryW(path)?;
56 this.write_scalar(Scalar::from_i32(result), dest)?;
61 let &[which] = check_arg_count(args)?;
62 let which = this.read_scalar(which)?.to_i32()?;
63 // We just make this the identity function, so we know later in `WriteFile`
65 this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
68 let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?;
69 this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore
70 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
71 let buf = this.read_scalar(buf)?.check_init()?;
72 let n = this.read_scalar(n)?.to_u32()?;
73 let written_place = this.deref_operand(written_ptr)?;
74 // Spec says to always write `0` first.
75 this.write_null(written_place.into())?;
76 let written = if handle == -11 || handle == -12 {
78 use std::io::{self, Write};
80 let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
81 let res = if handle == -11 {
82 io::stdout().write(buf_cont)
84 io::stderr().write(buf_cont)
86 res.ok().map(|n| n as u32)
88 throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported")
90 // If there was no error, write back how much was written.
91 if let Some(n) = written {
92 this.write_scalar(Scalar::from_u32(n), written_place.into())?;
94 // Return whether this was a success.
96 Scalar::from_i32(if written.is_some() { 1 } else { 0 }),
103 let &[handle, flags, size] = check_arg_count(args)?;
104 this.read_scalar(handle)?.to_machine_isize(this)?;
105 let flags = this.read_scalar(flags)?.to_u32()?;
106 let size = this.read_scalar(size)?.to_machine_usize(this)?;
107 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
108 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
109 this.write_scalar(res, dest)?;
112 let &[handle, flags, ptr] = check_arg_count(args)?;
113 this.read_scalar(handle)?.to_machine_isize(this)?;
114 this.read_scalar(flags)?.to_u32()?;
115 let ptr = this.read_scalar(ptr)?.check_init()?;
116 this.free(ptr, MiriMemoryKind::WinHeap)?;
117 this.write_scalar(Scalar::from_i32(1), dest)?;
120 let &[handle, flags, ptr, size] = check_arg_count(args)?;
121 this.read_scalar(handle)?.to_machine_isize(this)?;
122 this.read_scalar(flags)?.to_u32()?;
123 let ptr = this.read_scalar(ptr)?.check_init()?;
124 let size = this.read_scalar(size)?.to_machine_usize(this)?;
125 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
126 this.write_scalar(res, dest)?;
131 let &[error] = check_arg_count(args)?;
132 let error = this.read_scalar(error)?.check_init()?;
133 this.set_last_error(error)?;
136 let &[] = check_arg_count(args)?;
137 let last_error = this.get_last_error()?;
138 this.write_scalar(last_error, dest)?;
141 // Querying system information
143 let &[system_info] = check_arg_count(args)?;
144 let system_info = this.deref_operand(system_info)?;
145 // Initialize with `0`.
146 this.memory.write_bytes(
148 iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
150 // Set number of processors.
151 let dword_size = Size::from_bytes(4);
152 let num_cpus = this.mplace_field(system_info, 6)?;
153 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?;
156 // Thread-local storage
158 // This just creates a key; Windows does not natively support TLS destructors.
160 // Create key and return it.
161 let &[] = check_arg_count(args)?;
162 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
163 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
166 let &[key] = check_arg_count(args)?;
167 let key = u128::from(this.read_scalar(key)?.to_u32()?);
168 let active_thread = this.get_active_thread();
169 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
170 this.write_scalar(ptr, dest)?;
173 let &[key, new_ptr] = check_arg_count(args)?;
174 let key = u128::from(this.read_scalar(key)?.to_u32()?);
175 let active_thread = this.get_active_thread();
176 let new_ptr = this.read_scalar(new_ptr)?.check_init()?;
177 this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;
179 // Return success (`1`).
180 this.write_scalar(Scalar::from_i32(1), dest)?;
183 // Access to command-line arguments
184 "GetCommandLineW" => {
185 let &[] = check_arg_count(args)?;
187 this.machine.cmd_line.expect("machine must be initialized"),
192 // Time related shims
193 "GetSystemTimeAsFileTime" => {
194 #[allow(non_snake_case)]
195 let &[LPFILETIME] = check_arg_count(args)?;
196 this.GetSystemTimeAsFileTime(LPFILETIME)?;
198 "QueryPerformanceCounter" => {
199 #[allow(non_snake_case)]
200 let &[lpPerformanceCount] = check_arg_count(args)?;
201 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
202 this.write_scalar(Scalar::from_i32(result), dest)?;
204 "QueryPerformanceFrequency" => {
205 #[allow(non_snake_case)]
206 let &[lpFrequency] = check_arg_count(args)?;
207 let result = this.QueryPerformanceFrequency(lpFrequency)?;
208 this.write_scalar(Scalar::from_i32(result), dest)?;
211 // Synchronization primitives
212 "AcquireSRWLockExclusive" => {
213 let &[ptr] = check_arg_count(args)?;
214 this.AcquireSRWLockExclusive(ptr)?;
216 "ReleaseSRWLockExclusive" => {
217 let &[ptr] = check_arg_count(args)?;
218 this.ReleaseSRWLockExclusive(ptr)?;
220 "TryAcquireSRWLockExclusive" => {
221 let &[ptr] = check_arg_count(args)?;
222 let ret = this.TryAcquireSRWLockExclusive(ptr)?;
223 this.write_scalar(Scalar::from_u8(ret), dest)?;
225 "AcquireSRWLockShared" => {
226 let &[ptr] = check_arg_count(args)?;
227 this.AcquireSRWLockShared(ptr)?;
229 "ReleaseSRWLockShared" => {
230 let &[ptr] = check_arg_count(args)?;
231 this.ReleaseSRWLockShared(ptr)?;
233 "TryAcquireSRWLockShared" => {
234 let &[ptr] = check_arg_count(args)?;
235 let ret = this.TryAcquireSRWLockShared(ptr)?;
236 this.write_scalar(Scalar::from_u8(ret), dest)?;
239 // Dynamic symbol loading
240 "GetProcAddress" => {
241 #[allow(non_snake_case)]
242 let &[hModule, lpProcName] = check_arg_count(args)?;
243 this.read_scalar(hModule)?.to_machine_isize(this)?;
244 let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
245 if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
246 let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
247 this.write_scalar(Scalar::from(ptr), dest)?;
249 this.write_null(dest)?;
254 "SystemFunction036" => {
255 // The actual name of 'RtlGenRandom'
256 let &[ptr, len] = check_arg_count(args)?;
257 let ptr = this.read_scalar(ptr)?.check_init()?;
258 let len = this.read_scalar(len)?.to_u32()?;
259 this.gen_random(ptr, len.into())?;
260 this.write_scalar(Scalar::from_bool(true), dest)?;
262 "GetConsoleScreenBufferInfo" => {
263 // `term` needs this, so we fake it.
264 let &[console, buffer_info] = check_arg_count(args)?;
265 this.read_scalar(console)?.to_machine_isize(this)?;
266 this.deref_operand(buffer_info)?;
267 // Indicate an error.
268 // FIXME: we should set last_error, but to what?
269 this.write_null(dest)?;
271 "GetConsoleMode" => {
272 // Windows "isatty" (in libtest) needs this, so we fake it.
273 let &[console, mode] = check_arg_count(args)?;
274 this.read_scalar(console)?.to_machine_isize(this)?;
275 this.deref_operand(mode)?;
276 // Indicate an error.
277 // FIXME: we should set last_error, but to what?
278 this.write_null(dest)?;
280 "SwitchToThread" => {
281 let &[] = check_arg_count(args)?;
282 // Note that once Miri supports concurrency, this will need to return a nonzero
283 // value if this call does result in switching to another thread.
284 this.write_null(dest)?;
287 // Better error for attempts to create a thread
289 throw_unsup_format!("Miri does not support concurrency on Windows");
292 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
293 // These shims are enabled only when the caller is in the standard library.
294 "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
295 let &[] = check_arg_count(args)?;
296 // Just fake a HANDLE
297 this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
299 "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
300 #[allow(non_snake_case)]
301 let &[_lpModuleName] = check_arg_count(args)?;
302 // Pretend this does not exist / nothing happened, by returning zero.
303 this.write_null(dest)?;
305 "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
306 #[allow(non_snake_case)]
307 let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?;
308 // Pretend these does not exist / nothing happened, by returning zero.
309 this.write_null(dest)?;
311 "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
312 #[allow(non_snake_case)]
313 let &[_First, _Handler] = check_arg_count(args)?;
314 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
315 this.write_scalar(Scalar::from_machine_usize(1, this), dest)?;
317 "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
318 #[allow(non_snake_case)]
319 let &[_StackSizeInBytes] = check_arg_count(args)?;
320 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
321 this.write_scalar(Scalar::from_u32(1), dest)?;
323 | "InitializeCriticalSection"
324 | "EnterCriticalSection"
325 | "LeaveCriticalSection"
326 | "DeleteCriticalSection"
327 if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
328 #[allow(non_snake_case)]
329 let &[_lpCriticalSection] = check_arg_count(args)?;
330 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
331 // Nothing to do, not even a return value.
332 // (Windows locks are reentrant, and we have only 1 thread,
333 // so not doing any futher checks here is at least not incorrect.)
335 "TryEnterCriticalSection"
336 if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
337 #[allow(non_snake_case)]
338 let &[_lpCriticalSection] = check_arg_count(args)?;
339 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
340 // There is only one thread, so this always succeeds and returns TRUE.
341 this.write_scalar(Scalar::from_i32(1), dest)?;
344 _ => throw_unsup_format!("can't call foreign function: {}", link_name),