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();
25 // DWORD = ULONG = u32
29 // Environment related shims
30 "GetEnvironmentVariableW" => {
31 check_abi(abi, Abi::System { unwind: false })?;
32 let &[ref name, ref buf, ref size] = check_arg_count(args)?;
33 let result = this.GetEnvironmentVariableW(name, buf, size)?;
34 this.write_scalar(Scalar::from_u32(result), dest)?;
36 "SetEnvironmentVariableW" => {
37 check_abi(abi, Abi::System { unwind: false })?;
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 check_abi(abi, Abi::System { unwind: false })?;
44 let &[] = check_arg_count(args)?;
45 let result = this.GetEnvironmentStringsW()?;
46 this.write_scalar(result, dest)?;
48 "FreeEnvironmentStringsW" => {
49 check_abi(abi, Abi::System { unwind: false })?;
50 let &[ref env_block] = check_arg_count(args)?;
51 let result = this.FreeEnvironmentStringsW(env_block)?;
52 this.write_scalar(Scalar::from_i32(result), dest)?;
54 "GetCurrentDirectoryW" => {
55 check_abi(abi, Abi::System { unwind: false })?;
56 let &[ref size, ref buf] = check_arg_count(args)?;
57 let result = this.GetCurrentDirectoryW(size, buf)?;
58 this.write_scalar(Scalar::from_u32(result), dest)?;
60 "SetCurrentDirectoryW" => {
61 check_abi(abi, Abi::System { unwind: false })?;
62 let &[ref path] = check_arg_count(args)?;
63 let result = this.SetCurrentDirectoryW(path)?;
64 this.write_scalar(Scalar::from_i32(result), dest)?;
69 check_abi(abi, Abi::System { unwind: false })?;
70 let &[ref which] = check_arg_count(args)?;
71 let which = this.read_scalar(which)?.to_i32()?;
72 // We just make this the identity function, so we know later in `WriteFile`
74 this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
77 check_abi(abi, Abi::System { unwind: false })?;
78 let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] =
79 check_arg_count(args)?;
80 this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore
81 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
82 let buf = this.read_scalar(buf)?.check_init()?;
83 let n = this.read_scalar(n)?.to_u32()?;
84 let written_place = this.deref_operand(written_ptr)?;
85 // Spec says to always write `0` first.
86 this.write_null(&written_place.into())?;
87 let written = if handle == -11 || handle == -12 {
89 use std::io::{self, Write};
91 let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
92 let res = if handle == -11 {
93 io::stdout().write(buf_cont)
95 io::stderr().write(buf_cont)
97 res.ok().map(|n| n as u32)
100 "on Windows, writing to anything except stdout/stderr is not supported"
103 // If there was no error, write back how much was written.
104 if let Some(n) = written {
105 this.write_scalar(Scalar::from_u32(n), &written_place.into())?;
107 // Return whether this was a success.
108 this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?;
113 check_abi(abi, Abi::System { unwind: false })?;
114 let &[ref handle, ref flags, ref size] = check_arg_count(args)?;
115 this.read_scalar(handle)?.to_machine_isize(this)?;
116 let flags = this.read_scalar(flags)?.to_u32()?;
117 let size = this.read_scalar(size)?.to_machine_usize(this)?;
118 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
119 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
120 this.write_scalar(res, dest)?;
123 check_abi(abi, Abi::System { unwind: false })?;
124 let &[ref handle, ref flags, ref ptr] = 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 this.free(ptr, MiriMemoryKind::WinHeap)?;
129 this.write_scalar(Scalar::from_i32(1), dest)?;
132 check_abi(abi, Abi::System { unwind: false })?;
133 let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?;
134 this.read_scalar(handle)?.to_machine_isize(this)?;
135 this.read_scalar(flags)?.to_u32()?;
136 let ptr = this.read_scalar(ptr)?.check_init()?;
137 let size = this.read_scalar(size)?.to_machine_usize(this)?;
138 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
139 this.write_scalar(res, dest)?;
144 check_abi(abi, Abi::System { unwind: false })?;
145 let &[ref error] = check_arg_count(args)?;
146 let error = this.read_scalar(error)?.check_init()?;
147 this.set_last_error(error)?;
150 check_abi(abi, Abi::System { unwind: false })?;
151 let &[] = check_arg_count(args)?;
152 let last_error = this.get_last_error()?;
153 this.write_scalar(last_error, dest)?;
156 // Querying system information
158 check_abi(abi, Abi::System { unwind: false })?;
159 let &[ref system_info] = check_arg_count(args)?;
160 let system_info = this.deref_operand(system_info)?;
161 // Initialize with `0`.
162 this.memory.write_bytes(
164 iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
166 // Set number of processors.
167 let dword_size = Size::from_bytes(4);
168 let num_cpus = this.mplace_field(&system_info, 6)?;
169 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?;
172 // Thread-local storage
174 check_abi(abi, Abi::System { unwind: false })?;
175 // This just creates a key; Windows does not natively support TLS destructors.
177 // Create key and return it.
178 let &[] = check_arg_count(args)?;
179 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
180 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
183 check_abi(abi, Abi::System { unwind: false })?;
184 let &[ref key] = check_arg_count(args)?;
185 let key = u128::from(this.read_scalar(key)?.to_u32()?);
186 let active_thread = this.get_active_thread();
187 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
188 this.write_scalar(ptr, dest)?;
191 check_abi(abi, Abi::System { unwind: false })?;
192 let &[ref key, ref new_ptr] = check_arg_count(args)?;
193 let key = u128::from(this.read_scalar(key)?.to_u32()?);
194 let active_thread = this.get_active_thread();
195 let new_ptr = this.read_scalar(new_ptr)?.check_init()?;
196 this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;
198 // Return success (`1`).
199 this.write_scalar(Scalar::from_i32(1), dest)?;
202 // Access to command-line arguments
203 "GetCommandLineW" => {
204 check_abi(abi, Abi::System { unwind: false })?;
205 let &[] = check_arg_count(args)?;
207 this.machine.cmd_line.expect("machine must be initialized"),
212 // Time related shims
213 "GetSystemTimeAsFileTime" => {
214 check_abi(abi, Abi::System { unwind: false })?;
215 #[allow(non_snake_case)]
216 let &[ref LPFILETIME] = check_arg_count(args)?;
217 this.GetSystemTimeAsFileTime(LPFILETIME)?;
219 "QueryPerformanceCounter" => {
220 check_abi(abi, Abi::System { unwind: false })?;
221 #[allow(non_snake_case)]
222 let &[ref lpPerformanceCount] = check_arg_count(args)?;
223 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
224 this.write_scalar(Scalar::from_i32(result), dest)?;
226 "QueryPerformanceFrequency" => {
227 check_abi(abi, Abi::System { unwind: false })?;
228 #[allow(non_snake_case)]
229 let &[ref lpFrequency] = check_arg_count(args)?;
230 let result = this.QueryPerformanceFrequency(lpFrequency)?;
231 this.write_scalar(Scalar::from_i32(result), dest)?;
234 // Synchronization primitives
235 "AcquireSRWLockExclusive" => {
236 check_abi(abi, Abi::System { unwind: false })?;
237 let &[ref ptr] = check_arg_count(args)?;
238 this.AcquireSRWLockExclusive(ptr)?;
240 "ReleaseSRWLockExclusive" => {
241 check_abi(abi, Abi::System { unwind: false })?;
242 let &[ref ptr] = check_arg_count(args)?;
243 this.ReleaseSRWLockExclusive(ptr)?;
245 "TryAcquireSRWLockExclusive" => {
246 check_abi(abi, Abi::System { unwind: false })?;
247 let &[ref ptr] = check_arg_count(args)?;
248 let ret = this.TryAcquireSRWLockExclusive(ptr)?;
249 this.write_scalar(Scalar::from_u8(ret), dest)?;
251 "AcquireSRWLockShared" => {
252 check_abi(abi, Abi::System { unwind: false })?;
253 let &[ref ptr] = check_arg_count(args)?;
254 this.AcquireSRWLockShared(ptr)?;
256 "ReleaseSRWLockShared" => {
257 check_abi(abi, Abi::System { unwind: false })?;
258 let &[ref ptr] = check_arg_count(args)?;
259 this.ReleaseSRWLockShared(ptr)?;
261 "TryAcquireSRWLockShared" => {
262 check_abi(abi, Abi::System { unwind: false })?;
263 let &[ref ptr] = check_arg_count(args)?;
264 let ret = this.TryAcquireSRWLockShared(ptr)?;
265 this.write_scalar(Scalar::from_u8(ret), dest)?;
268 // Dynamic symbol loading
269 "GetProcAddress" => {
270 check_abi(abi, Abi::System { unwind: false })?;
271 #[allow(non_snake_case)]
272 let &[ref hModule, ref lpProcName] = check_arg_count(args)?;
273 this.read_scalar(hModule)?.to_machine_isize(this)?;
274 let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
275 if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
276 let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
277 this.write_scalar(Scalar::from(ptr), dest)?;
279 this.write_null(dest)?;
284 "SystemFunction036" => {
285 // This is really 'RtlGenRandom'.
286 check_abi(abi, Abi::System { unwind: false })?;
287 let &[ref ptr, ref len] = check_arg_count(args)?;
288 let ptr = this.read_scalar(ptr)?.check_init()?;
289 let len = this.read_scalar(len)?.to_u32()?;
290 this.gen_random(ptr, len.into())?;
291 this.write_scalar(Scalar::from_bool(true), dest)?;
293 "BCryptGenRandom" => {
294 check_abi(abi, Abi::System { unwind: false })?;
295 let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?;
296 let algorithm = this.read_scalar(algorithm)?;
297 let ptr = this.read_scalar(ptr)?.check_init()?;
298 let len = this.read_scalar(len)?.to_u32()?;
299 let flags = this.read_scalar(flags)?.to_u32()?;
301 // BCRYPT_USE_SYSTEM_PREFERRED_RNG
303 "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"
306 if algorithm.to_machine_usize(this)? != 0 {
308 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
311 this.gen_random(ptr, len.into())?;
312 this.write_null(dest)?; // STATUS_SUCCESS
314 "GetConsoleScreenBufferInfo" => {
315 check_abi(abi, Abi::System { unwind: false })?;
316 // `term` needs this, so we fake it.
317 let &[ref console, ref buffer_info] = check_arg_count(args)?;
318 this.read_scalar(console)?.to_machine_isize(this)?;
319 this.deref_operand(buffer_info)?;
320 // Indicate an error.
321 // FIXME: we should set last_error, but to what?
322 this.write_null(dest)?;
324 "GetConsoleMode" => {
325 check_abi(abi, Abi::System { unwind: false })?;
326 // Windows "isatty" (in libtest) needs this, so we fake it.
327 let &[ref console, ref mode] = check_arg_count(args)?;
328 this.read_scalar(console)?.to_machine_isize(this)?;
329 this.deref_operand(mode)?;
330 // Indicate an error.
331 // FIXME: we should set last_error, but to what?
332 this.write_null(dest)?;
334 "SwitchToThread" => {
335 check_abi(abi, Abi::System { unwind: false })?;
336 let &[] = check_arg_count(args)?;
337 // Note that once Miri supports concurrency, this will need to return a nonzero
338 // value if this call does result in switching to another thread.
339 this.write_null(dest)?;
342 // Better error for attempts to create a thread
344 check_abi(abi, Abi::System { unwind: false })?;
345 throw_unsup_format!("Miri does not support concurrency on Windows");
348 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
349 // These shims are enabled only when the caller is in the standard library.
351 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
353 check_abi(abi, Abi::System { unwind: false })?;
354 let &[] = check_arg_count(args)?;
355 // Just fake a HANDLE
356 this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
358 "SetConsoleTextAttribute"
359 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
361 check_abi(abi, Abi::System { unwind: false })?;
362 #[allow(non_snake_case)]
363 let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?;
364 // Pretend these does not exist / nothing happened, by returning zero.
365 this.write_null(dest)?;
367 "AddVectoredExceptionHandler"
368 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
370 check_abi(abi, Abi::System { unwind: false })?;
371 #[allow(non_snake_case)]
372 let &[ref _First, ref _Handler] = check_arg_count(args)?;
373 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
374 this.write_scalar(Scalar::from_machine_usize(1, this), dest)?;
376 "SetThreadStackGuarantee"
377 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
379 check_abi(abi, Abi::System { unwind: false })?;
380 #[allow(non_snake_case)]
381 let &[_StackSizeInBytes] = check_arg_count(args)?;
382 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
383 this.write_scalar(Scalar::from_u32(1), dest)?;
385 | "InitializeCriticalSection"
386 | "EnterCriticalSection"
387 | "LeaveCriticalSection"
388 | "DeleteCriticalSection"
389 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
391 check_abi(abi, Abi::System { unwind: false })?;
392 #[allow(non_snake_case)]
393 let &[ref _lpCriticalSection] = check_arg_count(args)?;
395 this.get_total_thread_count(),
397 "concurrency on Windows is not supported"
399 // Nothing to do, not even a return value.
400 // (Windows locks are reentrant, and we have only 1 thread,
401 // so not doing any futher checks here is at least not incorrect.)
403 "TryEnterCriticalSection"
404 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
406 check_abi(abi, Abi::System { unwind: false })?;
407 #[allow(non_snake_case)]
408 let &[ref _lpCriticalSection] = check_arg_count(args)?;
410 this.get_total_thread_count(),
412 "concurrency on Windows is not supported"
414 // There is only one thread, so this always succeeds and returns TRUE.
415 this.write_scalar(Scalar::from_i32(1), dest)?;
418 _ => throw_unsup_format!("can't call foreign function: {}", link_name),