]> git.lizzy.rs Git - rust.git/blob - src/shims/windows/foreign_items.rs
Auto merge of #1830 - RalfJung:readme, r=RalfJung
[rust.git] / src / shims / windows / foreign_items.rs
1 use std::iter;
2
3 use rustc_middle::mir;
4 use rustc_target::abi::Size;
5 use rustc_target::spec::abi::Abi;
6
7 use crate::*;
8 use helpers::check_arg_count;
9 use shims::foreign_items::EmulateByNameResult;
10 use shims::windows::sync::EvalContextExt as _;
11
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(
15         &mut self,
16         link_name: &str,
17         abi: Abi,
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();
23
24         // Windows API stubs.
25         // HANDLE = isize
26         // DWORD = ULONG = u32
27         // BOOL = i32
28         // BOOLEAN = u8
29         match link_name {
30             // Environment related shims
31             "GetEnvironmentVariableW" => {
32                 this.check_abi(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)?;
36             }
37             "SetEnvironmentVariableW" => {
38                 this.check_abi(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)?;
42             }
43             "GetEnvironmentStringsW" => {
44                 this.check_abi(abi, Abi::System { unwind: false })?;
45                 let &[] = check_arg_count(args)?;
46                 let result = this.GetEnvironmentStringsW()?;
47                 this.write_scalar(result, dest)?;
48             }
49             "FreeEnvironmentStringsW" => {
50                 this.check_abi(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)?;
54             }
55             "GetCurrentDirectoryW" => {
56                 this.check_abi(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)?;
60             }
61             "SetCurrentDirectoryW" => {
62                 this.check_abi(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)?;
66             }
67
68             // File related shims
69             "GetStdHandle" => {
70                 this.check_abi(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`
74                 // which one it is.
75                 this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
76             }
77             "WriteFile" => {
78                 this.check_abi(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 {
89                     // stdout/stderr
90                     use std::io::{self, Write};
91
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)
95                     } else {
96                         io::stderr().write(buf_cont)
97                     };
98                     res.ok().map(|n| n as u32)
99                 } else {
100                     throw_unsup_format!(
101                         "on Windows, writing to anything except stdout/stderr is not supported"
102                     )
103                 };
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())?;
107                 }
108                 // Return whether this was a success.
109                 this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?;
110             }
111
112             // Allocation
113             "HeapAlloc" => {
114                 this.check_abi(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)?;
122             }
123             "HeapFree" => {
124                 this.check_abi(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)?;
131             }
132             "HeapReAlloc" => {
133                 this.check_abi(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)?;
141             }
142
143             // errno
144             "SetLastError" => {
145                 this.check_abi(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)?;
149             }
150             "GetLastError" => {
151                 this.check_abi(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)?;
155             }
156
157             // Querying system information
158             "GetSystemInfo" => {
159                 this.check_abi(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(
164                     system_info.ptr,
165                     iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
166                 )?;
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())?;
171             }
172
173             // Thread-local storage
174             "TlsAlloc" => {
175                 this.check_abi(abi, Abi::System { unwind: false })?;
176                 // This just creates a key; Windows does not natively support TLS destructors.
177
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)?;
182             }
183             "TlsGetValue" => {
184                 this.check_abi(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)?;
190             }
191             "TlsSetValue" => {
192                 this.check_abi(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)?)?;
198
199                 // Return success (`1`).
200                 this.write_scalar(Scalar::from_i32(1), dest)?;
201             }
202
203             // Access to command-line arguments
204             "GetCommandLineW" => {
205                 this.check_abi(abi, Abi::System { unwind: false })?;
206                 let &[] = check_arg_count(args)?;
207                 this.write_scalar(
208                     this.machine.cmd_line.expect("machine must be initialized"),
209                     dest,
210                 )?;
211             }
212
213             // Time related shims
214             "GetSystemTimeAsFileTime" => {
215                 this.check_abi(abi, Abi::System { unwind: false })?;
216                 #[allow(non_snake_case)]
217                 let &[ref LPFILETIME] = check_arg_count(args)?;
218                 this.GetSystemTimeAsFileTime(LPFILETIME)?;
219             }
220             "QueryPerformanceCounter" => {
221                 this.check_abi(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)?;
226             }
227             "QueryPerformanceFrequency" => {
228                 this.check_abi(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)?;
233             }
234
235             // Synchronization primitives
236             "AcquireSRWLockExclusive" => {
237                 this.check_abi(abi, Abi::System { unwind: false })?;
238                 let &[ref ptr] = check_arg_count(args)?;
239                 this.AcquireSRWLockExclusive(ptr)?;
240             }
241             "ReleaseSRWLockExclusive" => {
242                 this.check_abi(abi, Abi::System { unwind: false })?;
243                 let &[ref ptr] = check_arg_count(args)?;
244                 this.ReleaseSRWLockExclusive(ptr)?;
245             }
246             "TryAcquireSRWLockExclusive" => {
247                 this.check_abi(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)?;
251             }
252             "AcquireSRWLockShared" => {
253                 this.check_abi(abi, Abi::System { unwind: false })?;
254                 let &[ref ptr] = check_arg_count(args)?;
255                 this.AcquireSRWLockShared(ptr)?;
256             }
257             "ReleaseSRWLockShared" => {
258                 this.check_abi(abi, Abi::System { unwind: false })?;
259                 let &[ref ptr] = check_arg_count(args)?;
260                 this.ReleaseSRWLockShared(ptr)?;
261             }
262             "TryAcquireSRWLockShared" => {
263                 this.check_abi(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)?;
267             }
268
269             // Dynamic symbol loading
270             "GetProcAddress" => {
271                 this.check_abi(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)?;
279                 } else {
280                     this.write_null(dest)?;
281                 }
282             }
283
284             // Miscellaneous
285             "SystemFunction036" => {
286                 // This is really 'RtlGenRandom'.
287                 this.check_abi(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)?;
293             }
294             "BCryptGenRandom" => {
295                 this.check_abi(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()?;
301                 if flags != 2 {
302                     //      ^ BCRYPT_USE_SYSTEM_PREFERRED_RNG
303                     throw_unsup_format!(
304                         "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"
305                     );
306                 }
307                 if algorithm.to_machine_usize(this)? != 0 {
308                     throw_unsup_format!(
309                         "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
310                     );
311                 }
312                 this.gen_random(ptr, len.into())?;
313                 this.write_null(dest)?; // STATUS_SUCCESS
314             }
315             "GetConsoleScreenBufferInfo" => {
316                 this.check_abi(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)?;
324             }
325             "GetConsoleMode" => {
326                 this.check_abi(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)?;
334             }
335             "SwitchToThread" => {
336                 this.check_abi(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)?;
341             }
342
343             // Better error for attempts to create a thread
344             "CreateThread" => {
345                 this.check_abi(abi, Abi::System { unwind: false })?;
346
347                 this.handle_unsupported("can't create threads on Windows")?;
348                 return Ok(EmulateByNameResult::AlreadyJumped);
349             }
350
351             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
352             // These shims are enabled only when the caller is in the standard library.
353             "GetProcessHeap" if this.frame_in_std() => {
354                 this.check_abi(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)?;
358             }
359             "SetConsoleTextAttribute" if this.frame_in_std() => {
360                 this.check_abi(abi, Abi::System { unwind: false })?;
361                 #[allow(non_snake_case)]
362                 let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?;
363                 // Pretend these does not exist / nothing happened, by returning zero.
364                 this.write_null(dest)?;
365             }
366             "AddVectoredExceptionHandler" if this.frame_in_std() => {
367                 this.check_abi(abi, Abi::System { unwind: false })?;
368                 #[allow(non_snake_case)]
369                 let &[ref _First, ref _Handler] = check_arg_count(args)?;
370                 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
371                 this.write_scalar(Scalar::from_machine_usize(1, this), dest)?;
372             }
373             "SetThreadStackGuarantee" if this.frame_in_std() => {
374                 this.check_abi(abi, Abi::System { unwind: false })?;
375                 #[allow(non_snake_case)]
376                 let &[_StackSizeInBytes] = check_arg_count(args)?;
377                 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
378                 this.write_scalar(Scalar::from_u32(1), dest)?;
379             }
380             | "InitializeCriticalSection"
381             | "EnterCriticalSection"
382             | "LeaveCriticalSection"
383             | "DeleteCriticalSection"
384                 if this.frame_in_std() =>
385             {
386                 this.check_abi(abi, Abi::System { unwind: false })?;
387                 #[allow(non_snake_case)]
388                 let &[ref _lpCriticalSection] = check_arg_count(args)?;
389                 assert_eq!(
390                     this.get_total_thread_count(),
391                     1,
392                     "concurrency on Windows is not supported"
393                 );
394                 // Nothing to do, not even a return value.
395                 // (Windows locks are reentrant, and we have only 1 thread,
396                 // so not doing any futher checks here is at least not incorrect.)
397             }
398             "TryEnterCriticalSection" if this.frame_in_std() => {
399                 this.check_abi(abi, Abi::System { unwind: false })?;
400                 #[allow(non_snake_case)]
401                 let &[ref _lpCriticalSection] = check_arg_count(args)?;
402                 assert_eq!(
403                     this.get_total_thread_count(),
404                     1,
405                     "concurrency on Windows is not supported"
406                 );
407                 // There is only one thread, so this always succeeds and returns TRUE.
408                 this.write_scalar(Scalar::from_i32(1), dest)?;
409             }
410
411             _ => return Ok(EmulateByNameResult::NotSupported),
412         }
413
414         Ok(EmulateByNameResult::NeedsJumping)
415     }
416 }