4 use rustc_target::abi::Size;
7 use helpers::check_arg_count;
9 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
10 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
11 fn emulate_foreign_item_by_name(
14 args: &[OpTy<'tcx, Tag>],
15 dest: PlaceTy<'tcx, Tag>,
16 _ret: mir::BasicBlock,
17 ) -> InterpResult<'tcx, bool> {
18 let this = self.eval_context_mut();
22 // DWORD = ULONG = u32
26 // Environment related shims
27 "GetEnvironmentVariableW" => {
28 let &[name, buf, size] = check_arg_count(args)?;
29 let result = this.GetEnvironmentVariableW(name, buf, size)?;
30 this.write_scalar(Scalar::from_u32(result), dest)?;
32 "SetEnvironmentVariableW" => {
33 let &[name, value] = check_arg_count(args)?;
34 let result = this.SetEnvironmentVariableW(name, value)?;
35 this.write_scalar(Scalar::from_i32(result), dest)?;
37 "GetEnvironmentStringsW" => {
38 let &[] = check_arg_count(args)?;
39 let result = this.GetEnvironmentStringsW()?;
40 this.write_scalar(result, dest)?;
42 "FreeEnvironmentStringsW" => {
43 let &[env_block] = check_arg_count(args)?;
44 let result = this.FreeEnvironmentStringsW(env_block)?;
45 this.write_scalar(Scalar::from_i32(result), dest)?;
47 "GetCurrentDirectoryW" => {
48 let &[size, buf] = check_arg_count(args)?;
49 let result = this.GetCurrentDirectoryW(size, buf)?;
50 this.write_scalar(Scalar::from_u32(result), dest)?;
52 "SetCurrentDirectoryW" => {
53 let &[path] = check_arg_count(args)?;
54 let result = this.SetCurrentDirectoryW(path)?;
55 this.write_scalar(Scalar::from_i32(result), dest)?;
60 let &[which] = check_arg_count(args)?;
61 let which = this.read_scalar(which)?.to_i32()?;
62 // We just make this the identity function, so we know later in `WriteFile`
64 this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
67 let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?;
68 this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore
69 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
70 let buf = this.read_scalar(buf)?.not_undef()?;
71 let n = this.read_scalar(n)?.to_u32()?;
72 let written_place = this.deref_operand(written_ptr)?;
73 // Spec says to always write `0` first.
74 this.write_null(written_place.into())?;
75 let written = if handle == -11 || handle == -12 {
77 use std::io::{self, Write};
79 let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
80 let res = if handle == -11 {
81 io::stdout().write(buf_cont)
83 io::stderr().write(buf_cont)
85 res.ok().map(|n| n as u32)
87 throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported")
89 // If there was no error, write back how much was written.
90 if let Some(n) = written {
91 this.write_scalar(Scalar::from_u32(n), written_place.into())?;
93 // Return whether this was a success.
95 Scalar::from_i32(if written.is_some() { 1 } else { 0 }),
102 let &[handle, flags, size] = check_arg_count(args)?;
103 this.read_scalar(handle)?.to_machine_isize(this)?;
104 let flags = this.read_scalar(flags)?.to_u32()?;
105 let size = this.read_scalar(size)?.to_machine_usize(this)?;
106 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
107 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
108 this.write_scalar(res, dest)?;
111 let &[handle, flags, ptr] = check_arg_count(args)?;
112 this.read_scalar(handle)?.to_machine_isize(this)?;
113 this.read_scalar(flags)?.to_u32()?;
114 let ptr = this.read_scalar(ptr)?.not_undef()?;
115 this.free(ptr, MiriMemoryKind::WinHeap)?;
116 this.write_scalar(Scalar::from_i32(1), dest)?;
119 let &[handle, flags, ptr, size] = check_arg_count(args)?;
120 this.read_scalar(handle)?.to_machine_isize(this)?;
121 this.read_scalar(flags)?.to_u32()?;
122 let ptr = this.read_scalar(ptr)?.not_undef()?;
123 let size = this.read_scalar(size)?.to_machine_usize(this)?;
124 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
125 this.write_scalar(res, dest)?;
130 let &[error] = check_arg_count(args)?;
131 let error = this.read_scalar(error)?.not_undef()?;
132 this.set_last_error(error)?;
135 let &[] = check_arg_count(args)?;
136 let last_error = this.get_last_error()?;
137 this.write_scalar(last_error, dest)?;
140 // Querying system information
142 let &[system_info] = check_arg_count(args)?;
143 let system_info = this.deref_operand(system_info)?;
144 // Initialize with `0`.
145 this.memory.write_bytes(
147 iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
149 // Set number of processors.
150 let dword_size = Size::from_bytes(4);
151 let num_cpus = this.mplace_field(system_info, 6)?;
152 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?;
155 // Thread-local storage
157 // This just creates a key; Windows does not natively support TLS destructors.
159 // Create key and return it.
160 let &[] = check_arg_count(args)?;
161 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
162 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
165 let &[key] = check_arg_count(args)?;
166 let key = u128::from(this.read_scalar(key)?.to_u32()?);
167 let active_thread = this.get_active_thread();
168 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
169 this.write_scalar(ptr, dest)?;
172 let &[key, new_ptr] = check_arg_count(args)?;
173 let key = u128::from(this.read_scalar(key)?.to_u32()?);
174 let active_thread = this.get_active_thread();
175 let new_ptr = this.read_scalar(new_ptr)?.not_undef()?;
176 this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;
178 // Return success (`1`).
179 this.write_scalar(Scalar::from_i32(1), dest)?;
182 // Access to command-line arguments
183 "GetCommandLineW" => {
184 let &[] = check_arg_count(args)?;
186 this.machine.cmd_line.expect("machine must be initialized"),
191 // Time related shims
192 "GetSystemTimeAsFileTime" => {
193 #[allow(non_snake_case)]
194 let &[LPFILETIME] = check_arg_count(args)?;
195 this.GetSystemTimeAsFileTime(LPFILETIME)?;
197 "QueryPerformanceCounter" => {
198 #[allow(non_snake_case)]
199 let &[lpPerformanceCount] = check_arg_count(args)?;
200 let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
201 this.write_scalar(Scalar::from_i32(result), dest)?;
203 "QueryPerformanceFrequency" => {
204 #[allow(non_snake_case)]
205 let &[lpFrequency] = check_arg_count(args)?;
206 let result = this.QueryPerformanceFrequency(lpFrequency)?;
207 this.write_scalar(Scalar::from_i32(result), dest)?;
210 // Dynamic symbol loading
211 "GetProcAddress" => {
212 #[allow(non_snake_case)]
213 let &[hModule, lpProcName] = check_arg_count(args)?;
214 this.read_scalar(hModule)?.to_machine_isize(this)?;
215 let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?;
216 if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? {
217 let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
218 this.write_scalar(Scalar::from(ptr), dest)?;
220 this.write_null(dest)?;
225 "SystemFunction036" => {
226 // The actual name of 'RtlGenRandom'
227 let &[ptr, len] = check_arg_count(args)?;
228 let ptr = this.read_scalar(ptr)?.not_undef()?;
229 let len = this.read_scalar(len)?.to_u32()?;
230 this.gen_random(ptr, len.into())?;
231 this.write_scalar(Scalar::from_bool(true), dest)?;
233 "GetConsoleScreenBufferInfo" => {
234 // `term` needs this, so we fake it.
235 let &[console, buffer_info] = check_arg_count(args)?;
236 this.read_scalar(console)?.to_machine_isize(this)?;
237 this.deref_operand(buffer_info)?;
238 // Indicate an error.
239 // FIXME: we should set last_error, but to what?
240 this.write_null(dest)?;
242 "GetConsoleMode" => {
243 // Windows "isatty" (in libtest) needs this, so we fake it.
244 let &[console, mode] = check_arg_count(args)?;
245 this.read_scalar(console)?.to_machine_isize(this)?;
246 this.deref_operand(mode)?;
247 // Indicate an error.
248 // FIXME: we should set last_error, but to what?
249 this.write_null(dest)?;
251 "SwitchToThread" => {
252 let &[] = check_arg_count(args)?;
253 // Note that once Miri supports concurrency, this will need to return a nonzero
254 // value if this call does result in switching to another thread.
255 this.write_null(dest)?;
258 // Better error for attempts to create a thread
260 throw_unsup_format!("Miri does not support threading");
263 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
264 // These shims are enabled only when the caller is in the standard library.
265 "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
266 let &[] = check_arg_count(args)?;
267 // Just fake a HANDLE
268 this.write_scalar(Scalar::from_machine_isize(1, this), dest)?;
270 "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
271 #[allow(non_snake_case)]
272 let &[_lpModuleName] = check_arg_count(args)?;
273 // Pretend this does not exist / nothing happened, by returning zero.
274 this.write_null(dest)?;
276 "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
277 #[allow(non_snake_case)]
278 let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?;
279 // Pretend these does not exist / nothing happened, by returning zero.
280 this.write_null(dest)?;
282 "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
283 #[allow(non_snake_case)]
284 let &[_First, _Handler] = check_arg_count(args)?;
285 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
286 this.write_scalar(Scalar::from_machine_usize(1, this), dest)?;
288 | "InitializeCriticalSection"
289 | "EnterCriticalSection"
290 | "LeaveCriticalSection"
291 | "DeleteCriticalSection"
292 if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
293 #[allow(non_snake_case)]
294 let &[_lpCriticalSection] = check_arg_count(args)?;
295 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported");
296 // Nothing to do, not even a return value.
297 // (Windows locks are reentrant, and we have only 1 thread,
298 // so not doing any futher checks here is at least not incorrect.)
300 "TryEnterCriticalSection"
301 if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
302 #[allow(non_snake_case)]
303 let &[_lpCriticalSection] = check_arg_count(args)?;
304 assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported");
305 // There is only one thread, so this always succeeds and returns TRUE.
306 this.write_scalar(Scalar::from_i32(1), dest)?;
309 _ => throw_unsup_format!("can't call foreign function: {}", link_name),