]> git.lizzy.rs Git - rust.git/blob - src/shims/windows/foreign_items.rs
Auto merge of #1801 - RalfJung:rustfmt, r=oli-obk
[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_abi, check_arg_count};
9 use shims::windows::sync::EvalContextExt as _;
10
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(
14         &mut self,
15         link_name: &str,
16         abi: Abi,
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();
22
23         // Windows API stubs.
24         // HANDLE = isize
25         // DWORD = ULONG = u32
26         // BOOL = i32
27         // BOOLEAN = u8
28         match link_name {
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)?;
35             }
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)?;
41             }
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)?;
47             }
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)?;
53             }
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)?;
59             }
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)?;
65             }
66
67             // File related shims
68             "GetStdHandle" => {
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`
73                 // which one it is.
74                 this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
75             }
76             "WriteFile" => {
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 {
88                     // stdout/stderr
89                     use std::io::{self, Write};
90
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)
94                     } else {
95                         io::stderr().write(buf_cont)
96                     };
97                     res.ok().map(|n| n as u32)
98                 } else {
99                     throw_unsup_format!(
100                         "on Windows, writing to anything except stdout/stderr is not supported"
101                     )
102                 };
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())?;
106                 }
107                 // Return whether this was a success.
108                 this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?;
109             }
110
111             // Allocation
112             "HeapAlloc" => {
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)?;
121             }
122             "HeapFree" => {
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)?;
130             }
131             "HeapReAlloc" => {
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)?;
140             }
141
142             // errno
143             "SetLastError" => {
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)?;
148             }
149             "GetLastError" => {
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)?;
154             }
155
156             // Querying system information
157             "GetSystemInfo" => {
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(
163                     system_info.ptr,
164                     iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
165                 )?;
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())?;
170             }
171
172             // Thread-local storage
173             "TlsAlloc" => {
174                 check_abi(abi, Abi::System { unwind: false })?;
175                 // This just creates a key; Windows does not natively support TLS destructors.
176
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)?;
181             }
182             "TlsGetValue" => {
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)?;
189             }
190             "TlsSetValue" => {
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)?)?;
197
198                 // Return success (`1`).
199                 this.write_scalar(Scalar::from_i32(1), dest)?;
200             }
201
202             // Access to command-line arguments
203             "GetCommandLineW" => {
204                 check_abi(abi, Abi::System { unwind: false })?;
205                 let &[] = check_arg_count(args)?;
206                 this.write_scalar(
207                     this.machine.cmd_line.expect("machine must be initialized"),
208                     dest,
209                 )?;
210             }
211
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)?;
218             }
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)?;
225             }
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)?;
232             }
233
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)?;
239             }
240             "ReleaseSRWLockExclusive" => {
241                 check_abi(abi, Abi::System { unwind: false })?;
242                 let &[ref ptr] = check_arg_count(args)?;
243                 this.ReleaseSRWLockExclusive(ptr)?;
244             }
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)?;
250             }
251             "AcquireSRWLockShared" => {
252                 check_abi(abi, Abi::System { unwind: false })?;
253                 let &[ref ptr] = check_arg_count(args)?;
254                 this.AcquireSRWLockShared(ptr)?;
255             }
256             "ReleaseSRWLockShared" => {
257                 check_abi(abi, Abi::System { unwind: false })?;
258                 let &[ref ptr] = check_arg_count(args)?;
259                 this.ReleaseSRWLockShared(ptr)?;
260             }
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)?;
266             }
267
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)?;
278                 } else {
279                     this.write_null(dest)?;
280                 }
281             }
282
283             // Miscellaneous
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)?;
292             }
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()?;
300                 if flags != 2 {
301                     // BCRYPT_USE_SYSTEM_PREFERRED_RNG
302                     throw_unsup_format!(
303                         "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"
304                     );
305                 }
306                 if algorithm.to_machine_usize(this)? != 0 {
307                     throw_unsup_format!(
308                         "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"
309                     );
310                 }
311                 this.gen_random(ptr, len.into())?;
312                 this.write_null(dest)?; // STATUS_SUCCESS
313             }
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)?;
323             }
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)?;
333             }
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)?;
340             }
341
342             // Better error for attempts to create a thread
343             "CreateThread" => {
344                 check_abi(abi, Abi::System { unwind: false })?;
345                 throw_unsup_format!("Miri does not support concurrency on Windows");
346             }
347
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.
350             "GetProcessHeap"
351                 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
352             {
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)?;
357             }
358             "SetConsoleTextAttribute"
359                 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
360             {
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)?;
366             }
367             "AddVectoredExceptionHandler"
368                 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
369             {
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)?;
375             }
376             "SetThreadStackGuarantee"
377                 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
378             {
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)?;
384             }
385             | "InitializeCriticalSection"
386             | "EnterCriticalSection"
387             | "LeaveCriticalSection"
388             | "DeleteCriticalSection"
389                 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
390             {
391                 check_abi(abi, Abi::System { unwind: false })?;
392                 #[allow(non_snake_case)]
393                 let &[ref _lpCriticalSection] = check_arg_count(args)?;
394                 assert_eq!(
395                     this.get_total_thread_count(),
396                     1,
397                     "concurrency on Windows is not supported"
398                 );
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.)
402             }
403             "TryEnterCriticalSection"
404                 if this.frame().instance.to_string().starts_with("std::sys::windows::") =>
405             {
406                 check_abi(abi, Abi::System { unwind: false })?;
407                 #[allow(non_snake_case)]
408                 let &[ref _lpCriticalSection] = check_arg_count(args)?;
409                 assert_eq!(
410                     this.get_total_thread_count(),
411                     1,
412                     "concurrency on Windows is not supported"
413                 );
414                 // There is only one thread, so this always succeeds and returns TRUE.
415                 this.write_scalar(Scalar::from_i32(1), dest)?;
416             }
417
418             _ => throw_unsup_format!("can't call foreign function: {}", link_name),
419         }
420
421         Ok(true)
422     }
423 }