4 use rustc_target::abi::Size;
5 use rustc_target::spec::abi::Abi;
8 use helpers::{check_abi, check_arg_count};
9 use shims::windows::sync::EvalContextExt as _;
11 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
12 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
13 fn emulate_foreign_item_by_name(
17 args: &[OpTy<'tcx, Tag>],
18 dest: &PlaceTy<'tcx, Tag>,
19 _ret: mir::BasicBlock,
20 ) -> InterpResult<'tcx, bool> {
21 let this = self.eval_context_mut();
23 check_abi(abi, Abi::System { unwind: false })?;
27 // DWORD = ULONG = u32
31 // Environment related shims
32 "GetEnvironmentVariableW" => {
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 let &[ref name, ref value] = check_arg_count(args)?;
39 let result = this.SetEnvironmentVariableW(name, value)?;
40 this.write_scalar(Scalar::from_i32(result), dest)?;
42 "GetEnvironmentStringsW" => {
43 let &[] = check_arg_count(args)?;
44 let result = this.GetEnvironmentStringsW()?;
45 this.write_scalar(result, dest)?;
47 "FreeEnvironmentStringsW" => {
48 let &[ref env_block] = check_arg_count(args)?;
49 let result = this.FreeEnvironmentStringsW(env_block)?;
50 this.write_scalar(Scalar::from_i32(result), dest)?;
52 "GetCurrentDirectoryW" => {
53 let &[ref size, ref buf] = check_arg_count(args)?;
54 let result = this.GetCurrentDirectoryW(size, buf)?;
55 this.write_scalar(Scalar::from_u32(result), dest)?;
57 "SetCurrentDirectoryW" => {
58 let &[ref path] = check_arg_count(args)?;
59 let result = this.SetCurrentDirectoryW(path)?;
60 this.write_scalar(Scalar::from_i32(result), dest)?;
65 let &[ref which] = check_arg_count(args)?;
66 let which = this.read_scalar(which)?.to_i32()?;
67 // We just make this the identity function, so we know later in `WriteFile`
69 this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
72 let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?;
73 this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore
74 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
75 let buf = this.read_scalar(buf)?.check_init()?;
76 let n = this.read_scalar(n)?.to_u32()?;
77 let written_place = this.deref_operand(written_ptr)?;
78 // Spec says to always write `0` first.
79 this.write_null(&written_place.into())?;
80 let written = if handle == -11 || handle == -12 {
82 use std::io::{self, Write};
84 let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
85 let res = if handle == -11 {
86 io::stdout().write(buf_cont)
88 io::stderr().write(buf_cont)
90 res.ok().map(|n| n as u32)
92 throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported")
94 // If there was no error, write back how much was written.
95 if let Some(n) = written {
96 this.write_scalar(Scalar::from_u32(n), &written_place.into())?;
98 // Return whether this was a success.
100 Scalar::from_i32(if written.is_some() { 1 } else { 0 }),
107 let &[ref handle, ref flags, ref size] = check_arg_count(args)?;
108 this.read_scalar(handle)?.to_machine_isize(this)?;
109 let flags = this.read_scalar(flags)?.to_u32()?;
110 let size = this.read_scalar(size)?.to_machine_usize(this)?;
111 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
112 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
113 this.write_scalar(res, dest)?;
116 let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?;
117 this.read_scalar(handle)?.to_machine_isize(this)?;
118 this.read_scalar(flags)?.to_u32()?;
119 let ptr = this.read_scalar(ptr)?.check_init()?;
120 this.free(ptr, MiriMemoryKind::WinHeap)?;
121 this.write_scalar(Scalar::from_i32(1), dest)?;
124 let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?;
125 this.read_scalar(handle)?.to_machine_isize(this)?;
126 this.read_scalar(flags)?.to_u32()?;
127 let ptr = this.read_scalar(ptr)?.check_init()?;
128 let size = this.read_scalar(size)?.to_machine_usize(this)?;
129 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
130 this.write_scalar(res, dest)?;
135 let &[ref error] = check_arg_count(args)?;
136 let error = this.read_scalar(error)?.check_init()?;
137 this.set_last_error(error)?;
140 let &[] = check_arg_count(args)?;
141 let last_error = this.get_last_error()?;
142 this.write_scalar(last_error, dest)?;
145 // Querying system information
147 let &[ref system_info] = check_arg_count(args)?;
148 let system_info = this.deref_operand(system_info)?;
149 // Initialize with `0`.
150 this.memory.write_bytes(
152 iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
154 // Set number of processors.
155 let dword_size = Size::from_bytes(4);
156 let num_cpus = this.mplace_field(&system_info, 6)?;
157 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?;
160 // Thread-local storage
162 // This just creates a key; Windows does not natively support TLS destructors.
164 // Create key and return it.
165 let &[] = check_arg_count(args)?;
166 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
167 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
170 let &[ref key] = check_arg_count(args)?;
171 let key = u128::from(this.read_scalar(key)?.to_u32()?);
172 let active_thread = this.get_active_thread();
173 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
174 this.write_scalar(ptr, dest)?;
177 let &[ref key, ref new_ptr] = check_arg_count(args)?;
178 let key = u128::from(this.read_scalar(key)?.to_u32()?);
179 let active_thread = this.get_active_thread();
180 let new_ptr = this.read_scalar(new_ptr)?.check_init()?;
181 this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;
183 // Return success (`1`).
184 this.write_scalar(Scalar::from_i32(1), dest)?;
187 // Access to command-line arguments
188 "GetCommandLineW" => {
189 let &[] = check_arg_count(args)?;
191 this.machine.cmd_line.expect("machine must be initialized"),
196 // Time related shims
197 "GetSystemTimeAsFileTime" => {
198 #[allow(non_snake_case)]
199 let &[ref LPFILETIME] = check_arg_count(args)?;
200 this.GetSystemTimeAsFileTime(LPFILETIME)?;
202 "QueryPerformanceCounter" => {
203 #[allow(non_snake_case)]
204 let &[ref lpPerformanceCount] = check_arg_count(args)?;
205 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
206 this.write_scalar(Scalar::from_i32(result), dest)?;
208 "QueryPerformanceFrequency" => {
209 #[allow(non_snake_case)]
210 let &[ref lpFrequency] = check_arg_count(args)?;
211 let result = this.QueryPerformanceFrequency(lpFrequency)?;
212 this.write_scalar(Scalar::from_i32(result), dest)?;
215 // Synchronization primitives
216 "AcquireSRWLockExclusive" => {
217 let &[ref ptr] = check_arg_count(args)?;
218 this.AcquireSRWLockExclusive(ptr)?;
220 "ReleaseSRWLockExclusive" => {
221 let &[ref ptr] = check_arg_count(args)?;
222 this.ReleaseSRWLockExclusive(ptr)?;
224 "TryAcquireSRWLockExclusive" => {
225 let &[ref ptr] = check_arg_count(args)?;
226 let ret = this.TryAcquireSRWLockExclusive(ptr)?;
227 this.write_scalar(Scalar::from_u8(ret), dest)?;
229 "AcquireSRWLockShared" => {
230 let &[ref ptr] = check_arg_count(args)?;
231 this.AcquireSRWLockShared(ptr)?;
233 "ReleaseSRWLockShared" => {
234 let &[ref ptr] = check_arg_count(args)?;
235 this.ReleaseSRWLockShared(ptr)?;
237 "TryAcquireSRWLockShared" => {
238 let &[ref ptr] = check_arg_count(args)?;
239 let ret = this.TryAcquireSRWLockShared(ptr)?;
240 this.write_scalar(Scalar::from_u8(ret), dest)?;
243 // Dynamic symbol loading
244 "GetProcAddress" => {
245 #[allow(non_snake_case)]
246 let &[ref hModule, ref lpProcName] = check_arg_count(args)?;
247 this.read_scalar(hModule)?.to_machine_isize(this)?;
248 let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
249 if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
250 let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
251 this.write_scalar(Scalar::from(ptr), dest)?;
253 this.write_null(dest)?;
258 "SystemFunction036" => {
259 // The actual name of 'RtlGenRandom'
260 let &[ref ptr, ref len] = check_arg_count(args)?;
261 let ptr = this.read_scalar(ptr)?.check_init()?;
262 let len = this.read_scalar(len)?.to_u32()?;
263 this.gen_random(ptr, len.into())?;
264 this.write_scalar(Scalar::from_bool(true), dest)?;
266 "GetConsoleScreenBufferInfo" => {
267 // `term` needs this, so we fake it.
268 let &[ref console, ref buffer_info] = check_arg_count(args)?;
269 this.read_scalar(console)?.to_machine_isize(this)?;
270 this.deref_operand(buffer_info)?;
271 // Indicate an error.
272 // FIXME: we should set last_error, but to what?
273 this.write_null(dest)?;
275 "GetConsoleMode" => {
276 // Windows "isatty" (in libtest) needs this, so we fake it.
277 let &[ref console, ref mode] = check_arg_count(args)?;
278 this.read_scalar(console)?.to_machine_isize(this)?;
279 this.deref_operand(mode)?;
280 // Indicate an error.
281 // FIXME: we should set last_error, but to what?
282 this.write_null(dest)?;
284 "SwitchToThread" => {
285 let &[] = check_arg_count(args)?;
286 // Note that once Miri supports concurrency, this will need to return a nonzero
287 // value if this call does result in switching to another thread.
288 this.write_null(dest)?;
291 // Better error for attempts to create a thread
293 throw_unsup_format!("Miri does not support concurrency on Windows");
296 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
297 // These shims are enabled only when the caller is in the standard library.
298 "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
299 let &[] = check_arg_count(args)?;
300 // Just fake a HANDLE
301 this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
303 "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
304 #[allow(non_snake_case)]
305 let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?;
306 // Pretend these does not exist / nothing happened, by returning zero.
307 this.write_null(dest)?;
309 "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
310 #[allow(non_snake_case)]
311 let &[ref _First, ref _Handler] = check_arg_count(args)?;
312 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
313 this.write_scalar(Scalar::from_machine_usize(1, this), dest)?;
315 "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
316 #[allow(non_snake_case)]
317 let &[_StackSizeInBytes] = check_arg_count(args)?;
318 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
319 this.write_scalar(Scalar::from_u32(1), dest)?;
321 | "InitializeCriticalSection"
322 | "EnterCriticalSection"
323 | "LeaveCriticalSection"
324 | "DeleteCriticalSection"
325 if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
326 #[allow(non_snake_case)]
327 let &[ref _lpCriticalSection] = check_arg_count(args)?;
328 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
329 // Nothing to do, not even a return value.
330 // (Windows locks are reentrant, and we have only 1 thread,
331 // so not doing any futher checks here is at least not incorrect.)
333 "TryEnterCriticalSection"
334 if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
335 #[allow(non_snake_case)]
336 let &[ref _lpCriticalSection] = check_arg_count(args)?;
337 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
338 // There is only one thread, so this always succeeds and returns TRUE.
339 this.write_scalar(Scalar::from_i32(1), dest)?;
342 _ => throw_unsup_format!("can't call foreign function: {}", link_name),