4 use rustc_span::Symbol;
5 use rustc_target::abi::Size;
6 use rustc_target::spec::abi::Abi;
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
29 match &*link_name.as_str() {
30 // Environment related shims
31 "GetEnvironmentVariableW" => {
32 let &[ref name, ref buf, ref size] =
33 this.check_shim(abi, Abi::System { unwind: false }, link_name, 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] =
39 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
40 let result = this.SetEnvironmentVariableW(name, value)?;
41 this.write_scalar(Scalar::from_i32(result), dest)?;
43 "GetEnvironmentStringsW" => {
44 let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
45 let result = this.GetEnvironmentStringsW()?;
46 this.write_scalar(result, dest)?;
48 "FreeEnvironmentStringsW" => {
49 let &[ref env_block] =
50 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
51 let result = this.FreeEnvironmentStringsW(env_block)?;
52 this.write_scalar(Scalar::from_i32(result), dest)?;
54 "GetCurrentDirectoryW" => {
55 let &[ref size, ref buf] =
56 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
57 let result = this.GetCurrentDirectoryW(size, buf)?;
58 this.write_scalar(Scalar::from_u32(result), dest)?;
60 "SetCurrentDirectoryW" => {
62 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
63 let result = this.SetCurrentDirectoryW(path)?;
64 this.write_scalar(Scalar::from_i32(result), dest)?;
70 this.check_shim(abi, Abi::System { unwind: false }, link_name, 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 let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] =
78 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
79 this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore
80 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
81 let buf = this.read_scalar(buf)?.check_init()?;
82 let n = this.read_scalar(n)?.to_u32()?;
83 let written_place = this.deref_operand(written_ptr)?;
84 // Spec says to always write `0` first.
85 this.write_null(&written_place.into())?;
86 let written = if handle == -11 || handle == -12 {
88 use std::io::{self, Write};
90 let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
91 let res = if handle == -11 {
92 io::stdout().write(buf_cont)
94 io::stderr().write(buf_cont)
96 res.ok().map(|n| n as u32)
99 "on Windows, writing to anything except stdout/stderr is not supported"
102 // If there was no error, write back how much was written.
103 if let Some(n) = written {
104 this.write_scalar(Scalar::from_u32(n), &written_place.into())?;
106 // Return whether this was a success.
107 this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?;
112 let &[ref handle, ref flags, ref size] =
113 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
114 this.read_scalar(handle)?.to_machine_isize(this)?;
115 let flags = this.read_scalar(flags)?.to_u32()?;
116 let size = this.read_scalar(size)?.to_machine_usize(this)?;
117 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
118 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
119 this.write_scalar(res, dest)?;
122 let &[ref handle, ref flags, ref ptr] =
123 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
124 this.read_scalar(handle)?.to_machine_isize(this)?;
125 this.read_scalar(flags)?.to_u32()?;
126 let ptr = this.read_scalar(ptr)?.check_init()?;
127 this.free(ptr, MiriMemoryKind::WinHeap)?;
128 this.write_scalar(Scalar::from_i32(1), dest)?;
131 let &[ref handle, ref flags, ref ptr, ref size] =
132 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
133 this.read_scalar(handle)?.to_machine_isize(this)?;
134 this.read_scalar(flags)?.to_u32()?;
135 let ptr = this.read_scalar(ptr)?.check_init()?;
136 let size = this.read_scalar(size)?.to_machine_usize(this)?;
137 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
138 this.write_scalar(res, dest)?;
144 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
145 let error = this.read_scalar(error)?.check_init()?;
146 this.set_last_error(error)?;
149 let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
150 let last_error = this.get_last_error()?;
151 this.write_scalar(last_error, dest)?;
154 // Querying system information
156 let &[ref system_info] =
157 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
158 let system_info = this.deref_operand(system_info)?;
159 // Initialize with `0`.
160 this.memory.write_bytes(
162 iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
164 // Set number of processors.
165 let dword_size = Size::from_bytes(4);
166 let num_cpus = this.mplace_field(&system_info, 6)?;
167 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?;
170 // Thread-local storage
172 // This just creates a key; Windows does not natively support TLS destructors.
174 // Create key and return it.
175 let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
176 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
177 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
181 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
182 let key = u128::from(this.read_scalar(key)?.to_u32()?);
183 let active_thread = this.get_active_thread();
184 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
185 this.write_scalar(ptr, dest)?;
188 let &[ref key, ref new_ptr] =
189 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
190 let key = u128::from(this.read_scalar(key)?.to_u32()?);
191 let active_thread = this.get_active_thread();
192 let new_ptr = this.read_scalar(new_ptr)?.check_init()?;
193 this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;
195 // Return success (`1`).
196 this.write_scalar(Scalar::from_i32(1), dest)?;
199 // Access to command-line arguments
200 "GetCommandLineW" => {
201 let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
203 this.machine.cmd_line.expect("machine must be initialized"),
208 // Time related shims
209 "GetSystemTimeAsFileTime" => {
210 #[allow(non_snake_case)]
211 let &[ref LPFILETIME] =
212 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
213 this.GetSystemTimeAsFileTime(LPFILETIME)?;
215 "QueryPerformanceCounter" => {
216 #[allow(non_snake_case)]
217 let &[ref lpPerformanceCount] =
218 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
219 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
220 this.write_scalar(Scalar::from_i32(result), dest)?;
222 "QueryPerformanceFrequency" => {
223 #[allow(non_snake_case)]
224 let &[ref lpFrequency] =
225 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
226 let result = this.QueryPerformanceFrequency(lpFrequency)?;
227 this.write_scalar(Scalar::from_i32(result), dest)?;
230 // Synchronization primitives
231 "AcquireSRWLockExclusive" => {
233 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
234 this.AcquireSRWLockExclusive(ptr)?;
236 "ReleaseSRWLockExclusive" => {
238 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
239 this.ReleaseSRWLockExclusive(ptr)?;
241 "TryAcquireSRWLockExclusive" => {
243 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
244 let ret = this.TryAcquireSRWLockExclusive(ptr)?;
245 this.write_scalar(Scalar::from_u8(ret), dest)?;
247 "AcquireSRWLockShared" => {
249 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
250 this.AcquireSRWLockShared(ptr)?;
252 "ReleaseSRWLockShared" => {
254 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
255 this.ReleaseSRWLockShared(ptr)?;
257 "TryAcquireSRWLockShared" => {
259 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
260 let ret = this.TryAcquireSRWLockShared(ptr)?;
261 this.write_scalar(Scalar::from_u8(ret), dest)?;
264 // Dynamic symbol loading
265 "GetProcAddress" => {
266 #[allow(non_snake_case)]
267 let &[ref hModule, ref lpProcName] =
268 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
269 this.read_scalar(hModule)?.to_machine_isize(this)?;
270 let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
271 if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
272 let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
273 this.write_scalar(Scalar::from(ptr), dest)?;
275 this.write_null(dest)?;
280 "SystemFunction036" => {
281 // This is really 'RtlGenRandom'.
282 let &[ref ptr, ref len] =
283 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
284 let ptr = this.read_scalar(ptr)?.check_init()?;
285 let len = this.read_scalar(len)?.to_u32()?;
286 this.gen_random(ptr, len.into())?;
287 this.write_scalar(Scalar::from_bool(true), dest)?;
289 "BCryptGenRandom" => {
290 let &[ref algorithm, ref ptr, ref len, ref flags] =
291 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
292 let algorithm = this.read_scalar(algorithm)?;
293 let ptr = this.read_scalar(ptr)?.check_init()?;
294 let len = this.read_scalar(len)?.to_u32()?;
295 let flags = this.read_scalar(flags)?.to_u32()?;
297 // ^ BCRYPT_USE_SYSTEM_PREFERRED_RNG
299 "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"
302 if algorithm.to_machine_usize(this)? != 0 {
304 "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
307 this.gen_random(ptr, len.into())?;
308 this.write_null(dest)?; // STATUS_SUCCESS
310 "GetConsoleScreenBufferInfo" => {
311 // `term` needs this, so we fake it.
312 let &[ref console, ref buffer_info] =
313 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
314 this.read_scalar(console)?.to_machine_isize(this)?;
315 this.deref_operand(buffer_info)?;
316 // Indicate an error.
317 // FIXME: we should set last_error, but to what?
318 this.write_null(dest)?;
320 "GetConsoleMode" => {
321 // Windows "isatty" (in libtest) needs this, so we fake it.
322 let &[ref console, ref mode] =
323 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
324 this.read_scalar(console)?.to_machine_isize(this)?;
325 this.deref_operand(mode)?;
326 // Indicate an error.
327 // FIXME: we should set last_error, but to what?
328 this.write_null(dest)?;
330 "SwitchToThread" => {
331 let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
332 // Note that once Miri supports concurrency, this will need to return a nonzero
333 // value if this call does result in switching to another thread.
334 this.write_null(dest)?;
337 // Better error for attempts to create a thread
339 let &[_, _, _, _, _, _] =
340 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
342 this.handle_unsupported("can't create threads on Windows")?;
343 return Ok(EmulateByNameResult::AlreadyJumped);
346 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
347 // These shims are enabled only when the caller is in the standard library.
348 "GetProcessHeap" if this.frame_in_std() => {
349 let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
350 // Just fake a HANDLE
351 this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
353 "SetConsoleTextAttribute" if this.frame_in_std() => {
354 #[allow(non_snake_case)]
355 let &[ref _hConsoleOutput, ref _wAttribute] =
356 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
357 // Pretend these does not exist / nothing happened, by returning zero.
358 this.write_null(dest)?;
360 "AddVectoredExceptionHandler" if this.frame_in_std() => {
361 #[allow(non_snake_case)]
362 let &[ref _First, ref _Handler] =
363 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
364 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
365 this.write_scalar(Scalar::from_machine_usize(1, this), dest)?;
367 "SetThreadStackGuarantee" if this.frame_in_std() => {
368 #[allow(non_snake_case)]
369 let &[_StackSizeInBytes] =
370 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
371 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
372 this.write_scalar(Scalar::from_u32(1), dest)?;
374 | "InitializeCriticalSection"
375 | "EnterCriticalSection"
376 | "LeaveCriticalSection"
377 | "DeleteCriticalSection"
378 if this.frame_in_std() =>
380 #[allow(non_snake_case)]
381 let &[ref _lpCriticalSection] =
382 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
384 this.get_total_thread_count(),
386 "concurrency on Windows is not supported"
388 // Nothing to do, not even a return value.
389 // (Windows locks are reentrant, and we have only 1 thread,
390 // so not doing any futher checks here is at least not incorrect.)
392 "TryEnterCriticalSection" if this.frame_in_std() => {
393 #[allow(non_snake_case)]
394 let &[ref _lpCriticalSection] =
395 this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
397 this.get_total_thread_count(),
399 "concurrency on Windows is not supported"
401 // There is only one thread, so this always succeeds and returns TRUE.
402 this.write_scalar(Scalar::from_i32(1), dest)?;
405 _ => return Ok(EmulateByNameResult::NotSupported),
408 Ok(EmulateByNameResult::NeedsJumping)