4 use rustc_target::abi::Size;
5 use rustc_target::spec::abi::Abi;
8 use helpers::{check_abi, check_arg_count};
9 use shims::foreign_items::EmulateByNameResult;
10 use shims::windows::sync::EvalContextExt as _;
12 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
13 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
14 fn emulate_foreign_item_by_name(
18 args: &[OpTy<'tcx, Tag>],
19 dest: &PlaceTy<'tcx, Tag>,
20 _ret: mir::BasicBlock,
21 ) -> InterpResult<'tcx, EmulateByNameResult> {
22 let this = self.eval_context_mut();
26 // DWORD = ULONG = u32
30 // Environment related shims
31 "GetEnvironmentVariableW" => {
32 check_abi(this, abi, Abi::System { unwind: false })?;
33 let &[ref name, ref buf, ref size] = check_arg_count(args)?;
34 let result = this.GetEnvironmentVariableW(name, buf, size)?;
35 this.write_scalar(Scalar::from_u32(result), dest)?;
37 "SetEnvironmentVariableW" => {
38 check_abi(this, abi, Abi::System { unwind: false })?;
39 let &[ref name, ref value] = check_arg_count(args)?;
40 let result = this.SetEnvironmentVariableW(name, value)?;
41 this.write_scalar(Scalar::from_i32(result), dest)?;
43 "GetEnvironmentStringsW" => {
44 check_abi(this, abi, Abi::System { unwind: false })?;
45 let &[] = check_arg_count(args)?;
46 let result = this.GetEnvironmentStringsW()?;
47 this.write_scalar(result, dest)?;
49 "FreeEnvironmentStringsW" => {
50 check_abi(this, abi, Abi::System { unwind: false })?;
51 let &[ref env_block] = check_arg_count(args)?;
52 let result = this.FreeEnvironmentStringsW(env_block)?;
53 this.write_scalar(Scalar::from_i32(result), dest)?;
55 "GetCurrentDirectoryW" => {
56 check_abi(this, abi, Abi::System { unwind: false })?;
57 let &[ref size, ref buf] = check_arg_count(args)?;
58 let result = this.GetCurrentDirectoryW(size, buf)?;
59 this.write_scalar(Scalar::from_u32(result), dest)?;
61 "SetCurrentDirectoryW" => {
62 check_abi(this, abi, Abi::System { unwind: false })?;
63 let &[ref path] = check_arg_count(args)?;
64 let result = this.SetCurrentDirectoryW(path)?;
65 this.write_scalar(Scalar::from_i32(result), dest)?;
70 check_abi(this, abi, Abi::System { unwind: false })?;
71 let &[ref which] = check_arg_count(args)?;
72 let which = this.read_scalar(which)?.to_i32()?;
73 // We just make this the identity function, so we know later in `WriteFile`
75 this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
78 check_abi(this, abi, Abi::System { unwind: false })?;
79 let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] =
80 check_arg_count(args)?;
81 this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore
82 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
83 let buf = this.read_scalar(buf)?.check_init()?;
84 let n = this.read_scalar(n)?.to_u32()?;
85 let written_place = this.deref_operand(written_ptr)?;
86 // Spec says to always write `0` first.
87 this.write_null(&written_place.into())?;
88 let written = if handle == -11 || handle == -12 {
90 use std::io::{self, Write};
92 let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
93 let res = if handle == -11 {
94 io::stdout().write(buf_cont)
96 io::stderr().write(buf_cont)
98 res.ok().map(|n| n as u32)
101 "on Windows, writing to anything except stdout/stderr is not supported"
104 // If there was no error, write back how much was written.
105 if let Some(n) = written {
106 this.write_scalar(Scalar::from_u32(n), &written_place.into())?;
108 // Return whether this was a success.
109 this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?;
114 check_abi(this, abi, Abi::System { unwind: false })?;
115 let &[ref handle, ref flags, ref size] = check_arg_count(args)?;
116 this.read_scalar(handle)?.to_machine_isize(this)?;
117 let flags = this.read_scalar(flags)?.to_u32()?;
118 let size = this.read_scalar(size)?.to_machine_usize(this)?;
119 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
120 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
121 this.write_scalar(res, dest)?;
124 check_abi(this, abi, Abi::System { unwind: false })?;
125 let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?;
126 this.read_scalar(handle)?.to_machine_isize(this)?;
127 this.read_scalar(flags)?.to_u32()?;
128 let ptr = this.read_scalar(ptr)?.check_init()?;
129 this.free(ptr, MiriMemoryKind::WinHeap)?;
130 this.write_scalar(Scalar::from_i32(1), dest)?;
133 check_abi(this, abi, Abi::System { unwind: false })?;
134 let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?;
135 this.read_scalar(handle)?.to_machine_isize(this)?;
136 this.read_scalar(flags)?.to_u32()?;
137 let ptr = this.read_scalar(ptr)?.check_init()?;
138 let size = this.read_scalar(size)?.to_machine_usize(this)?;
139 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
140 this.write_scalar(res, dest)?;
145 check_abi(this, abi, Abi::System { unwind: false })?;
146 let &[ref error] = check_arg_count(args)?;
147 let error = this.read_scalar(error)?.check_init()?;
148 this.set_last_error(error)?;
151 check_abi(this, abi, Abi::System { unwind: false })?;
152 let &[] = check_arg_count(args)?;
153 let last_error = this.get_last_error()?;
154 this.write_scalar(last_error, dest)?;
157 // Querying system information
159 check_abi(this, abi, Abi::System { unwind: false })?;
160 let &[ref system_info] = check_arg_count(args)?;
161 let system_info = this.deref_operand(system_info)?;
162 // Initialize with `0`.
163 this.memory.write_bytes(
165 iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
167 // Set number of processors.
168 let dword_size = Size::from_bytes(4);
169 let num_cpus = this.mplace_field(&system_info, 6)?;
170 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?;
173 // Thread-local storage
175 check_abi(this, abi, Abi::System { unwind: false })?;
176 // This just creates a key; Windows does not natively support TLS destructors.
178 // Create key and return it.
179 let &[] = check_arg_count(args)?;
180 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
181 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
184 check_abi(this, abi, Abi::System { unwind: false })?;
185 let &[ref key] = check_arg_count(args)?;
186 let key = u128::from(this.read_scalar(key)?.to_u32()?);
187 let active_thread = this.get_active_thread();
188 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
189 this.write_scalar(ptr, dest)?;
192 check_abi(this, abi, Abi::System { unwind: false })?;
193 let &[ref key, ref new_ptr] = check_arg_count(args)?;
194 let key = u128::from(this.read_scalar(key)?.to_u32()?);
195 let active_thread = this.get_active_thread();
196 let new_ptr = this.read_scalar(new_ptr)?.check_init()?;
197 this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;
199 // Return success (`1`).
200 this.write_scalar(Scalar::from_i32(1), dest)?;
203 // Access to command-line arguments
204 "GetCommandLineW" => {
205 check_abi(this, abi, Abi::System { unwind: false })?;
206 let &[] = check_arg_count(args)?;
208 this.machine.cmd_line.expect("machine must be initialized"),
213 // Time related shims
214 "GetSystemTimeAsFileTime" => {
215 check_abi(this, abi, Abi::System { unwind: false })?;
216 #[allow(non_snake_case)]
217 let &[ref LPFILETIME] = check_arg_count(args)?;
218 this.GetSystemTimeAsFileTime(LPFILETIME)?;
220 "QueryPerformanceCounter" => {
221 check_abi(this, abi, Abi::System { unwind: false })?;
222 #[allow(non_snake_case)]
223 let &[ref lpPerformanceCount] = check_arg_count(args)?;
224 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
225 this.write_scalar(Scalar::from_i32(result), dest)?;
227 "QueryPerformanceFrequency" => {
228 check_abi(this, abi, Abi::System { unwind: false })?;
229 #[allow(non_snake_case)]
230 let &[ref lpFrequency] = check_arg_count(args)?;
231 let result = this.QueryPerformanceFrequency(lpFrequency)?;
232 this.write_scalar(Scalar::from_i32(result), dest)?;
235 // Synchronization primitives
236 "AcquireSRWLockExclusive" => {
237 check_abi(this, abi, Abi::System { unwind: false })?;
238 let &[ref ptr] = check_arg_count(args)?;
239 this.AcquireSRWLockExclusive(ptr)?;
241 "ReleaseSRWLockExclusive" => {
242 check_abi(this, abi, Abi::System { unwind: false })?;
243 let &[ref ptr] = check_arg_count(args)?;
244 this.ReleaseSRWLockExclusive(ptr)?;
246 "TryAcquireSRWLockExclusive" => {
247 check_abi(this, abi, Abi::System { unwind: false })?;
248 let &[ref ptr] = check_arg_count(args)?;
249 let ret = this.TryAcquireSRWLockExclusive(ptr)?;
250 this.write_scalar(Scalar::from_u8(ret), dest)?;
252 "AcquireSRWLockShared" => {
253 check_abi(this, abi, Abi::System { unwind: false })?;
254 let &[ref ptr] = check_arg_count(args)?;
255 this.AcquireSRWLockShared(ptr)?;
257 "ReleaseSRWLockShared" => {
258 check_abi(this, abi, Abi::System { unwind: false })?;
259 let &[ref ptr] = check_arg_count(args)?;
260 this.ReleaseSRWLockShared(ptr)?;
262 "TryAcquireSRWLockShared" => {
263 check_abi(this, abi, Abi::System { unwind: false })?;
264 let &[ref ptr] = check_arg_count(args)?;
265 let ret = this.TryAcquireSRWLockShared(ptr)?;
266 this.write_scalar(Scalar::from_u8(ret), dest)?;
269 // Dynamic symbol loading
270 "GetProcAddress" => {
271 check_abi(this, abi, Abi::System { unwind: false })?;
272 #[allow(non_snake_case)]
273 let &[ref hModule, ref lpProcName] = check_arg_count(args)?;
274 this.read_scalar(hModule)?.to_machine_isize(this)?;
275 let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
276 if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
277 let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
278 this.write_scalar(Scalar::from(ptr), dest)?;
280 this.write_null(dest)?;
285 "SystemFunction036" => {
286 // This is really 'RtlGenRandom'.
287 check_abi(this, abi, Abi::System { unwind: false })?;
288 let &[ref ptr, ref len] = check_arg_count(args)?;
289 let ptr = this.read_scalar(ptr)?.check_init()?;
290 let len = this.read_scalar(len)?.to_u32()?;
291 this.gen_random(ptr, len.into())?;
292 this.write_scalar(Scalar::from_bool(true), dest)?;
294 "BCryptGenRandom" => {
295 check_abi(this, abi, Abi::System { unwind: false })?;
296 let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?;
297 let algorithm = this.read_scalar(algorithm)?;
298 let ptr = this.read_scalar(ptr)?.check_init()?;
299 let len = this.read_scalar(len)?.to_u32()?;
300 let flags = this.read_scalar(flags)?.to_u32()?;
302 // ^ BCRYPT_USE_SYSTEM_PREFERRED_RNG
304 "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"
307 if algorithm.to_machine_usize(this)? != 0 {
309 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
312 this.gen_random(ptr, len.into())?;
313 this.write_null(dest)?; // STATUS_SUCCESS
315 "GetConsoleScreenBufferInfo" => {
316 check_abi(this, abi, Abi::System { unwind: false })?;
317 // `term` needs this, so we fake it.
318 let &[ref console, ref buffer_info] = check_arg_count(args)?;
319 this.read_scalar(console)?.to_machine_isize(this)?;
320 this.deref_operand(buffer_info)?;
321 // Indicate an error.
322 // FIXME: we should set last_error, but to what?
323 this.write_null(dest)?;
325 "GetConsoleMode" => {
326 check_abi(this, abi, Abi::System { unwind: false })?;
327 // Windows "isatty" (in libtest) needs this, so we fake it.
328 let &[ref console, ref mode] = check_arg_count(args)?;
329 this.read_scalar(console)?.to_machine_isize(this)?;
330 this.deref_operand(mode)?;
331 // Indicate an error.
332 // FIXME: we should set last_error, but to what?
333 this.write_null(dest)?;
335 "SwitchToThread" => {
336 check_abi(this, abi, Abi::System { unwind: false })?;
337 let &[] = check_arg_count(args)?;
338 // Note that once Miri supports concurrency, this will need to return a nonzero
339 // value if this call does result in switching to another thread.
340 this.write_null(dest)?;
343 // Better error for attempts to create a thread
345 check_abi(this, abi, Abi::System { unwind: false })?;
346 throw_unsup_format!("Miri does not support concurrency on Windows");
349 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
350 // These shims are enabled only when the caller is in the standard library.
352 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
354 check_abi(this, abi, Abi::System { unwind: false })?;
355 let &[] = check_arg_count(args)?;
356 // Just fake a HANDLE
357 this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
359 "SetConsoleTextAttribute"
360 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
362 check_abi(this, abi, Abi::System { unwind: false })?;
363 #[allow(non_snake_case)]
364 let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?;
365 // Pretend these does not exist / nothing happened, by returning zero.
366 this.write_null(dest)?;
368 "AddVectoredExceptionHandler"
369 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
371 check_abi(this, abi, Abi::System { unwind: false })?;
372 #[allow(non_snake_case)]
373 let &[ref _First, ref _Handler] = check_arg_count(args)?;
374 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
375 this.write_scalar(Scalar::from_machine_usize(1, this), dest)?;
377 "SetThreadStackGuarantee"
378 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
380 check_abi(this, abi, Abi::System { unwind: false })?;
381 #[allow(non_snake_case)]
382 let &[_StackSizeInBytes] = check_arg_count(args)?;
383 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
384 this.write_scalar(Scalar::from_u32(1), dest)?;
386 | "InitializeCriticalSection"
387 | "EnterCriticalSection"
388 | "LeaveCriticalSection"
389 | "DeleteCriticalSection"
390 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
392 check_abi(this, abi, Abi::System { unwind: false })?;
393 #[allow(non_snake_case)]
394 let &[ref _lpCriticalSection] = check_arg_count(args)?;
396 this.get_total_thread_count(),
398 "concurrency on Windows is not supported"
400 // Nothing to do, not even a return value.
401 // (Windows locks are reentrant, and we have only 1 thread,
402 // so not doing any futher checks here is at least not incorrect.)
404 "TryEnterCriticalSection"
405 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
407 check_abi(this, abi, Abi::System { unwind: false })?;
408 #[allow(non_snake_case)]
409 let &[ref _lpCriticalSection] = check_arg_count(args)?;
411 this.get_total_thread_count(),
413 "concurrency on Windows is not supported"
415 // There is only one thread, so this always succeeds and returns TRUE.
416 this.write_scalar(Scalar::from_i32(1), dest)?;
419 _ => return Ok(EmulateByNameResult::NotSupported),
422 Ok(EmulateByNameResult::NeedsJumping)