]> git.lizzy.rs Git - rust.git/blob - src/fn_call.rs
ae6aff10ac209728a85fb244e787fd19cf757709
[rust.git] / src / fn_call.rs
1 use rustc::ty;
2 use rustc::ty::layout::{Align, LayoutOf, Size};
3 use rustc::hir::def_id::DefId;
4 use rustc::mir;
5 use syntax::attr;
6
7 use rand::RngCore;
8
9 use crate::*;
10
11 impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {}
12 pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> {
13     fn find_fn(
14         &mut self,
15         instance: ty::Instance<'tcx>,
16         args: &[OpTy<'tcx, Tag>],
17         dest: Option<PlaceTy<'tcx, Tag>>,
18         ret: Option<mir::BasicBlock>,
19     ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
20         let this = self.eval_context_mut();
21         trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));
22
23         // First, run the common hooks also supported by CTFE.
24         if this.hook_fn(instance, args, dest)? {
25             this.goto_block(ret)?;
26             return Ok(None);
27         }
28         // There are some more lang items we want to hook that CTFE does not hook (yet).
29         if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
30             // FIXME: return a real value in case the target allocation has an
31             // alignment bigger than the one requested.
32             let n = u128::max_value();
33             let dest = dest.unwrap();
34             let n = this.truncate(n, dest.layout);
35             this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
36             this.goto_block(ret)?;
37             return Ok(None);
38         }
39
40         // Try to see if we can do something about foreign items.
41         if this.tcx.is_foreign_item(instance.def_id()) {
42             // An external function that we cannot find MIR for, but we can still run enough
43             // of them to make miri viable.
44             this.emulate_foreign_item(instance.def_id(), args, dest, ret)?;
45             // `goto_block` already handled.
46             return Ok(None);
47         }
48
49         // Otherwise, load the MIR.
50         Ok(Some(this.load_mir(instance.def)?))
51     }
52
53     /// Emulates calling a foreign item, failing if the item is not supported.
54     /// This function will handle `goto_block` if needed.
55     fn emulate_foreign_item(
56         &mut self,
57         def_id: DefId,
58         args: &[OpTy<'tcx, Tag>],
59         dest: Option<PlaceTy<'tcx, Tag>>,
60         ret: Option<mir::BasicBlock>,
61     ) -> EvalResult<'tcx> {
62         let this = self.eval_context_mut();
63         let attrs = this.tcx.get_attrs(def_id);
64         let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
65             Some(name) => name.as_str(),
66             None => this.tcx.item_name(def_id).as_str(),
67         };
68         // Strip linker suffixes (seen on 32-bit macOS).
69         let link_name = link_name.get().trim_end_matches("$UNIX2003");
70         let tcx = &{this.tcx.tcx};
71
72         // First: functions that could diverge.
73         match link_name {
74             "__rust_start_panic" | "panic_impl" => {
75                 return err!(MachineError("the evaluated program panicked".to_string()));
76             }
77             _ => if dest.is_none() {
78                 return err!(Unimplemented(
79                     format!("can't call diverging foreign function: {}", link_name),
80                 ));
81             }
82         }
83
84         // Next: functions that assume a ret and dest.
85         let dest = dest.expect("we already checked for a dest");
86         let ret = ret.expect("dest is `Some` but ret is `None`");
87         match link_name {
88             "malloc" => {
89                 let size = this.read_scalar(args[0])?.to_usize(this)?;
90                 if size == 0 {
91                     this.write_null(dest)?;
92                 } else {
93                     let align = this.tcx.data_layout.pointer_align.abi;
94                     let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into());
95                     this.write_scalar(Scalar::Ptr(ptr), dest)?;
96                 }
97             }
98             "calloc" => {
99                 let items = this.read_scalar(args[0])?.to_usize(this)?;
100                 let len = this.read_scalar(args[1])?.to_usize(this)?;
101                 let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?;
102
103                 if bytes == 0 {
104                     this.write_null(dest)?;
105                 } else {
106                     let size = Size::from_bytes(bytes);
107                     let align = this.tcx.data_layout.pointer_align.abi;
108                     let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into());
109                     this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?;
110                     this.write_scalar(Scalar::Ptr(ptr), dest)?;
111                 }
112             }
113             "posix_memalign" => {
114                 let ret = this.deref_operand(args[0])?;
115                 let align = this.read_scalar(args[1])?.to_usize(this)?;
116                 let size = this.read_scalar(args[2])?.to_usize(this)?;
117                 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
118                 if !align.is_power_of_two() {
119                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
120                 }
121                 if align < this.pointer_size().bytes() {
122                     return err!(MachineError(format!(
123                         "posix_memalign: alignment must be at least the size of a pointer, but is {}",
124                         align,
125                     )));
126                 }
127                 if size == 0 {
128                     this.write_null(ret.into())?;
129                 } else {
130                     let ptr = this.memory_mut().allocate(
131                         Size::from_bytes(size),
132                         Align::from_bytes(align).unwrap(),
133                         MiriMemoryKind::C.into()
134                     );
135                     this.write_scalar(Scalar::Ptr(ptr), ret.into())?;
136                 }
137                 this.write_null(dest)?;
138             }
139
140             "free" => {
141                 let ptr = this.read_scalar(args[0])?.not_undef()?;
142                 if !ptr.is_null_ptr(this) {
143                     this.memory_mut().deallocate(
144                         ptr.to_ptr()?,
145                         None,
146                         MiriMemoryKind::C.into(),
147                     )?;
148                 }
149             }
150             "realloc" => {
151                 let old_ptr = this.read_scalar(args[0])?.not_undef()?;
152                 let new_size = this.read_scalar(args[1])?.to_usize(this)?;
153                 let align = this.tcx.data_layout.pointer_align.abi;
154                 if old_ptr.is_null_ptr(this) {
155                     if new_size == 0 {
156                         this.write_null(dest)?;
157                     } else {
158                         let new_ptr = this.memory_mut().allocate(
159                             Size::from_bytes(new_size),
160                             align,
161                             MiriMemoryKind::C.into()
162                         );
163                         this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
164                     }
165                 } else {
166                     let old_ptr = old_ptr.to_ptr()?;
167                     let memory = this.memory_mut();
168                     let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64);
169                     if new_size == 0 {
170                         memory.deallocate(
171                             old_ptr,
172                             Some((old_size, align)),
173                             MiriMemoryKind::C.into(),
174                         )?;
175                         this.write_null(dest)?;
176                     } else {
177                         let new_ptr = memory.reallocate(
178                             old_ptr,
179                             old_size,
180                             align,
181                             Size::from_bytes(new_size),
182                             align,
183                             MiriMemoryKind::C.into(),
184                         )?;
185                         this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
186                     }
187                 }
188             }
189
190             "__rust_alloc" => {
191                 let size = this.read_scalar(args[0])?.to_usize(this)?;
192                 let align = this.read_scalar(args[1])?.to_usize(this)?;
193                 if size == 0 {
194                     return err!(HeapAllocZeroBytes);
195                 }
196                 if !align.is_power_of_two() {
197                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
198                 }
199                 let ptr = this.memory_mut()
200                     .allocate(
201                         Size::from_bytes(size),
202                         Align::from_bytes(align).unwrap(),
203                         MiriMemoryKind::Rust.into()
204                     );
205                 this.write_scalar(Scalar::Ptr(ptr), dest)?;
206             }
207             "__rust_alloc_zeroed" => {
208                 let size = this.read_scalar(args[0])?.to_usize(this)?;
209                 let align = this.read_scalar(args[1])?.to_usize(this)?;
210                 if size == 0 {
211                     return err!(HeapAllocZeroBytes);
212                 }
213                 if !align.is_power_of_two() {
214                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
215                 }
216                 let ptr = this.memory_mut()
217                     .allocate(
218                         Size::from_bytes(size),
219                         Align::from_bytes(align).unwrap(),
220                         MiriMemoryKind::Rust.into()
221                     );
222                 this.memory_mut()
223                     .get_mut(ptr.alloc_id)?
224                     .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?;
225                 this.write_scalar(Scalar::Ptr(ptr), dest)?;
226             }
227             "__rust_dealloc" => {
228                 let ptr = this.read_scalar(args[0])?.to_ptr()?;
229                 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
230                 let align = this.read_scalar(args[2])?.to_usize(this)?;
231                 if old_size == 0 {
232                     return err!(HeapAllocZeroBytes);
233                 }
234                 if !align.is_power_of_two() {
235                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
236                 }
237                 this.memory_mut().deallocate(
238                     ptr,
239                     Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
240                     MiriMemoryKind::Rust.into(),
241                 )?;
242             }
243             "__rust_realloc" => {
244                 let ptr = this.read_scalar(args[0])?.to_ptr()?;
245                 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
246                 let align = this.read_scalar(args[2])?.to_usize(this)?;
247                 let new_size = this.read_scalar(args[3])?.to_usize(this)?;
248                 if old_size == 0 || new_size == 0 {
249                     return err!(HeapAllocZeroBytes);
250                 }
251                 if !align.is_power_of_two() {
252                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
253                 }
254                 let new_ptr = this.memory_mut().reallocate(
255                     ptr,
256                     Size::from_bytes(old_size),
257                     Align::from_bytes(align).unwrap(),
258                     Size::from_bytes(new_size),
259                     Align::from_bytes(align).unwrap(),
260                     MiriMemoryKind::Rust.into(),
261                 )?;
262                 this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
263             }
264
265             "syscall" => {
266                 let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])?
267                     .expect("Failed to get libc::SYS_getrandom")
268                     .to_usize(this)?;
269
270                 // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
271                 // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
272                 match this.read_scalar(args[0])?.to_usize(this)? {
273                     id if id == sys_getrandom => {
274                         let ptr = this.read_scalar(args[1])?.to_ptr()?;
275                         let len = this.read_scalar(args[2])?.to_usize(this)?;
276
277                         // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
278                         // neither of which have any effect on our current PRNG
279                         let _flags = this.read_scalar(args[3])?.to_i32()?;
280
281                         if len > 0 {
282                             let data = gen_random(this, len as usize)?;
283                             this.memory_mut().get_mut(ptr.alloc_id)?
284                                         .write_bytes(tcx, ptr, &data)?;
285                         }
286
287                         this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
288                     }
289                     id => {
290                         return err!(Unimplemented(
291                             format!("miri does not support syscall ID {}", id),
292                         ))
293                     }
294                 }
295             }
296
297             "dlsym" => {
298                 let _handle = this.read_scalar(args[0])?;
299                 let symbol = this.read_scalar(args[1])?.to_ptr()?;
300                 let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?;
301                 let err = format!("bad c unicode symbol: {:?}", symbol_name);
302                 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
303                 return err!(Unimplemented(format!(
304                     "miri does not support dynamically loading libraries (requested symbol: {})",
305                     symbol_name
306                 )));
307             }
308
309             "__rust_maybe_catch_panic" => {
310                 // fn __rust_maybe_catch_panic(
311                 //     f: fn(*mut u8),
312                 //     data: *mut u8,
313                 //     data_ptr: *mut usize,
314                 //     vtable_ptr: *mut usize,
315                 // ) -> u32
316                 // We abort on panic, so not much is going on here, but we still have to call the closure.
317                 let f = this.read_scalar(args[0])?.to_ptr()?;
318                 let data = this.read_scalar(args[1])?.not_undef()?;
319                 let f_instance = this.memory().get_fn(f)?;
320                 this.write_null(dest)?;
321                 trace!("__rust_maybe_catch_panic: {:?}", f_instance);
322
323                 // Now we make a function call.
324                 // TODO: consider making this reusable? `InterpretCx::step` does something similar
325                 // for the TLS destructors, and of course `eval_main`.
326                 let mir = this.load_mir(f_instance.def)?;
327                 let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
328                 this.push_stack_frame(
329                     f_instance,
330                     mir.span,
331                     mir,
332                     Some(ret_place),
333                     // Directly return to caller.
334                     StackPopCleanup::Goto(Some(ret)),
335                 )?;
336                 let mut args = this.frame().mir.args_iter();
337
338                 let arg_local = args.next().ok_or_else(||
339                     InterpError::AbiViolation(
340                         "Argument to __rust_maybe_catch_panic does not take enough arguments."
341                             .to_owned(),
342                     ),
343                 )?;
344                 let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?;
345                 this.write_scalar(data, arg_dest)?;
346
347                 assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
348
349                 // We ourselves will return `0`, eventually (because we will not return if we paniced).
350                 this.write_null(dest)?;
351
352                 // Don't fall through, we do *not* want to `goto_block`!
353                 return Ok(());
354             }
355
356             "memcmp" => {
357                 let left = this.read_scalar(args[0])?.not_undef()?;
358                 let right = this.read_scalar(args[1])?.not_undef()?;
359                 let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?);
360
361                 let result = {
362                     let left_bytes = this.memory().read_bytes(left, n)?;
363                     let right_bytes = this.memory().read_bytes(right, n)?;
364
365                     use std::cmp::Ordering::*;
366                     match left_bytes.cmp(right_bytes) {
367                         Less => -1i32,
368                         Equal => 0,
369                         Greater => 1,
370                     }
371                 };
372
373                 this.write_scalar(
374                     Scalar::from_int(result, Size::from_bits(32)),
375                     dest,
376                 )?;
377             }
378
379             "memrchr" => {
380                 let ptr = this.read_scalar(args[0])?.not_undef()?;
381                 let val = this.read_scalar(args[1])?.to_i32()? as u8;
382                 let num = this.read_scalar(args[2])?.to_usize(this)?;
383                 if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?
384                     .iter().rev().position(|&c| c == val)
385                 {
386                     let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?;
387                     this.write_scalar(new_ptr, dest)?;
388                 } else {
389                     this.write_null(dest)?;
390                 }
391             }
392
393             "memchr" => {
394                 let ptr = this.read_scalar(args[0])?.not_undef()?;
395                 let val = this.read_scalar(args[1])?.to_i32()? as u8;
396                 let num = this.read_scalar(args[2])?.to_usize(this)?;
397                 let idx = this
398                     .memory()
399                     .read_bytes(ptr, Size::from_bytes(num))?
400                     .iter()
401                     .position(|&c| c == val);
402                 if let Some(idx) = idx {
403                     let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?;
404                     this.write_scalar(new_ptr, dest)?;
405                 } else {
406                     this.write_null(dest)?;
407                 }
408             }
409
410             "getenv" => {
411                 let result = {
412                     let name_ptr = this.read_scalar(args[0])?.to_ptr()?;
413                     let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
414                     match this.machine.env_vars.get(name) {
415                         Some(&var) => Scalar::Ptr(var),
416                         None => Scalar::ptr_null(&*this.tcx),
417                     }
418                 };
419                 this.write_scalar(result, dest)?;
420             }
421
422             "unsetenv" => {
423                 let mut success = None;
424                 {
425                     let name_ptr = this.read_scalar(args[0])?.not_undef()?;
426                     if !name_ptr.is_null_ptr(this) {
427                         let name_ptr = name_ptr.to_ptr()?;
428                         let name = this
429                             .memory()
430                             .get(name_ptr.alloc_id)?
431                             .read_c_str(tcx, name_ptr)?
432                             .to_owned();
433                         if !name.is_empty() && !name.contains(&b'=') {
434                             success = Some(this.machine.env_vars.remove(&name));
435                         }
436                     }
437                 }
438                 if let Some(old) = success {
439                     if let Some(var) = old {
440                         this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
441                     }
442                     this.write_null(dest)?;
443                 } else {
444                     this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
445                 }
446             }
447
448             "setenv" => {
449                 let mut new = None;
450                 {
451                     let name_ptr = this.read_scalar(args[0])?.not_undef()?;
452                     let value_ptr = this.read_scalar(args[1])?.to_ptr()?;
453                     let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?;
454                     if !name_ptr.is_null_ptr(this) {
455                         let name_ptr = name_ptr.to_ptr()?;
456                         let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
457                         if !name.is_empty() && !name.contains(&b'=') {
458                             new = Some((name.to_owned(), value.to_owned()));
459                         }
460                     }
461                 }
462                 if let Some((name, value)) = new {
463                     // `+1` for the null terminator.
464                     let value_copy = this.memory_mut().allocate(
465                         Size::from_bytes((value.len() + 1) as u64),
466                         Align::from_bytes(1).unwrap(),
467                         MiriMemoryKind::Env.into(),
468                     );
469                     {
470                         let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?;
471                         alloc.write_bytes(tcx, value_copy, &value)?;
472                         let trailing_zero_ptr = value_copy.offset(
473                             Size::from_bytes(value.len() as u64),
474                             tcx,
475                         )?;
476                         alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?;
477                     }
478                     if let Some(var) = this.machine.env_vars.insert(
479                         name.to_owned(),
480                         value_copy,
481                     )
482                     {
483                         this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
484                     }
485                     this.write_null(dest)?;
486                 } else {
487                     this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
488                 }
489             }
490
491             "write" => {
492                 let fd = this.read_scalar(args[0])?.to_i32()?;
493                 let buf = this.read_scalar(args[1])?.not_undef()?;
494                 let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?;
495                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
496                 let result = if fd == 1 || fd == 2 {
497                     // stdout/stderr
498                     use std::io::{self, Write};
499
500                     let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?;
501                     // We need to flush to make sure this actually appears on the screen
502                     let res = if fd == 1 {
503                         // Stdout is buffered, flush to make sure it appears on the screen.
504                         // This is the write() syscall of the interpreted program, we want it
505                         // to correspond to a write() syscall on the host -- there is no good
506                         // in adding extra buffering here.
507                         let res = io::stdout().write(buf_cont);
508                         io::stdout().flush().unwrap();
509                         res
510                     } else {
511                         // No need to flush, stderr is not buffered.
512                         io::stderr().write(buf_cont)
513                     };
514                     match res {
515                         Ok(n) => n as i64,
516                         Err(_) => -1,
517                     }
518                 } else {
519                     eprintln!("Miri: Ignored output to FD {}", fd);
520                     // Pretend it all went well.
521                     n as i64
522                 };
523                 // Now, `result` is the value we return back to the program.
524                 this.write_scalar(
525                     Scalar::from_int(result, dest.layout.size),
526                     dest,
527                 )?;
528             }
529
530             "strlen" => {
531                 let ptr = this.read_scalar(args[0])?.to_ptr()?;
532                 let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len();
533                 this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
534             }
535
536             // Some things needed for `sys::thread` initialization to go through.
537             "signal" | "sigaction" | "sigaltstack" => {
538                 this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
539             }
540
541             "sysconf" => {
542                 let name = this.read_scalar(args[0])?.to_i32()?;
543
544                 trace!("sysconf() called with name {}", name);
545                 // Cache the sysconf integers via Miri's global cache.
546                 let paths = &[
547                     (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
548                     (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
549                     (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
550                 ];
551                 let mut result = None;
552                 for &(path, path_value) in paths {
553                     if let Some(val) = this.eval_path_scalar(path)? {
554                         let val = val.to_i32()?;
555                         if val == name {
556                             result = Some(path_value);
557                             break;
558                         }
559
560                     }
561                 }
562                 if let Some(result) = result {
563                     this.write_scalar(result, dest)?;
564                 } else {
565                     return err!(Unimplemented(
566                         format!("Unimplemented sysconf name: {}", name),
567                     ));
568                 }
569             }
570
571             "isatty" => {
572                 this.write_null(dest)?;
573             }
574
575             // Hook pthread calls that go to the thread-local storage memory subsystem.
576             "pthread_key_create" => {
577                 let key_ptr = this.read_scalar(args[0])?.to_ptr()?;
578
579                 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
580                 let dtor = match this.read_scalar(args[1])?.not_undef()? {
581                     Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
582                     Scalar::Bits { bits: 0, size } => {
583                         assert_eq!(size as u64, this.memory().pointer_size().bytes());
584                         None
585                     },
586                     Scalar::Bits { .. } => return err!(ReadBytesAsPointer),
587                 };
588
589                 // Figure out how large a pthread TLS key actually is.
590                 // This is `libc::pthread_key_t`.
591                 let key_type = args[0].layout.ty
592                     .builtin_deref(true)
593                     .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))?
594                     .ty;
595                 let key_layout = this.layout_of(key_type)?;
596
597                 // Create key and write it into the memory where `key_ptr` wants it.
598                 let key = this.machine.tls.create_tls_key(dtor, tcx) as u128;
599                 if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
600                     return err!(OutOfTls);
601                 }
602
603                 this.memory().check_align(key_ptr.into(), key_layout.align.abi)?;
604                 this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
605                     tcx,
606                     key_ptr,
607                     Scalar::from_uint(key, key_layout.size).into(),
608                     key_layout.size,
609                 )?;
610
611                 // Return success (`0`).
612                 this.write_null(dest)?;
613             }
614             "pthread_key_delete" => {
615                 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
616                 this.machine.tls.delete_tls_key(key)?;
617                 // Return success (0)
618                 this.write_null(dest)?;
619             }
620             "pthread_getspecific" => {
621                 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
622                 let ptr = this.machine.tls.load_tls(key)?;
623                 this.write_scalar(ptr, dest)?;
624             }
625             "pthread_setspecific" => {
626                 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
627                 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
628                 this.machine.tls.store_tls(key, new_ptr)?;
629
630                 // Return success (`0`).
631                 this.write_null(dest)?;
632             }
633
634             // Determine stack base address.
635             "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
636             "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
637                 this.write_null(dest)?;
638             }
639             "pthread_attr_getstack" => {
640                 // Second argument is where we are supposed to write the stack size.
641                 let ptr = this.deref_operand(args[1])?;
642                 // Just any address.
643                 let stack_addr = Scalar::from_int(0x80000, args[1].layout.size);
644                 this.write_scalar(stack_addr, ptr.into())?;
645                 // Return success (`0`).
646                 this.write_null(dest)?;
647             }
648             "pthread_get_stackaddr_np" => {
649                 // Just any address.
650                 let stack_addr = Scalar::from_int(0x80000, dest.layout.size);
651                 this.write_scalar(stack_addr, dest)?;
652             }
653
654             // Stub out calls for condvar, mutex and rwlock, to just return `0`.
655             "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" |
656             "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" |
657             "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" |
658             "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" |
659             "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" |
660             "pthread_cond_destroy" => {
661                 this.write_null(dest)?;
662             }
663
664             // We don't support fork so we don't have to do anything for atfork.
665             "pthread_atfork" => {
666                 this.write_null(dest)?;
667             }
668
669             "mmap" => {
670                 // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
671                 let addr = this.read_scalar(args[0])?.not_undef()?;
672                 this.write_scalar(addr, dest)?;
673             }
674             "mprotect" => {
675                 this.write_null(dest)?;
676             }
677
678             // macOS API stubs.
679             "_tlv_atexit" => {
680                 // FIXME: register the destructor.
681             },
682             "_NSGetArgc" => {
683                 this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
684             },
685             "_NSGetArgv" => {
686                 this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
687             },
688
689             // Windows API stubs.
690             "SetLastError" => {
691                 let err = this.read_scalar(args[0])?.to_u32()?;
692                 this.machine.last_error = err;
693             }
694             "GetLastError" => {
695                 this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?;
696             }
697
698             "AddVectoredExceptionHandler" => {
699                 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
700                 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
701             },
702             "InitializeCriticalSection" |
703             "EnterCriticalSection" |
704             "LeaveCriticalSection" |
705             "DeleteCriticalSection" => {
706                 // Nothing to do, not even a return value.
707             },
708             "GetModuleHandleW" |
709             "GetProcAddress" |
710             "TryEnterCriticalSection" |
711             "GetConsoleScreenBufferInfo" |
712             "SetConsoleTextAttribute" => {
713                 // Pretend these do not exist / nothing happened, by returning zero.
714                 this.write_null(dest)?;
715             },
716             "GetSystemInfo" => {
717                 let system_info = this.deref_operand(args[0])?;
718                 let system_info_ptr = system_info.ptr.to_ptr()?;
719                 // Initialize with `0`.
720                 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
721                     .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
722                 // Set number of processors to `1`.
723                 let dword_size = Size::from_bytes(4);
724                 let offset = 2*dword_size + 3*tcx.pointer_size();
725                 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
726                     .write_scalar(
727                         tcx,
728                         system_info_ptr.offset(offset, tcx)?,
729                         Scalar::from_int(1, dword_size).into(),
730                         dword_size,
731                     )?;
732             }
733
734             "TlsAlloc" => {
735                 // This just creates a key; Windows does not natively support TLS destructors.
736
737                 // Create key and return it.
738                 let key = this.machine.tls.create_tls_key(None, tcx) as u128;
739
740                 // Figure out how large a TLS key actually is. This is `c::DWORD`.
741                 if dest.layout.size.bits() < 128
742                         && key >= (1u128 << dest.layout.size.bits() as u128) {
743                     return err!(OutOfTls);
744                 }
745                 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
746             }
747             "TlsGetValue" => {
748                 let key = this.read_scalar(args[0])?.to_u32()? as u128;
749                 let ptr = this.machine.tls.load_tls(key)?;
750                 this.write_scalar(ptr, dest)?;
751             }
752             "TlsSetValue" => {
753                 let key = this.read_scalar(args[0])?.to_u32()? as u128;
754                 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
755                 this.machine.tls.store_tls(key, new_ptr)?;
756
757                 // Return success (`1`).
758                 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
759             }
760             "GetStdHandle" => {
761                 let which = this.read_scalar(args[0])?.to_i32()?;
762                 // We just make this the identity function, so we know later in `WriteFile`
763                 // which one it is.
764                 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
765             }
766             "WriteFile" => {
767                 let handle = this.read_scalar(args[0])?.to_isize(this)?;
768                 let buf = this.read_scalar(args[1])?.not_undef()?;
769                 let n = this.read_scalar(args[2])?.to_u32()?;
770                 let written_place = this.deref_operand(args[3])?;
771                 // Spec says to always write `0` first.
772                 this.write_null(written_place.into())?;
773                 let written = if handle == -11 || handle == -12 {
774                     // stdout/stderr
775                     use std::io::{self, Write};
776
777                     let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
778                     let res = if handle == -11 {
779                         io::stdout().write(buf_cont)
780                     } else {
781                         io::stderr().write(buf_cont)
782                     };
783                     res.ok().map(|n| n as u32)
784                 } else {
785                     eprintln!("Miri: Ignored output to handle {}", handle);
786                     // Pretend it all went well.
787                     Some(n)
788                 };
789                 // If there was no error, write back how much was written.
790                 if let Some(n) = written {
791                     this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?;
792                 }
793                 // Return whether this was a success.
794                 this.write_scalar(
795                     Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
796                     dest,
797                 )?;
798             }
799             "GetConsoleMode" => {
800                 // Everything is a pipe.
801                 this.write_null(dest)?;
802             }
803             "GetEnvironmentVariableW" => {
804                 // This is not the env var you are looking for.
805                 this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
806                 this.write_null(dest)?;
807             }
808             "GetCommandLineW" => {
809                 this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
810             }
811             // The actual name of 'RtlGenRandom'
812             "SystemFunction036" => {
813                 let ptr = this.read_scalar(args[0])?.to_ptr()?;
814                 let len = this.read_scalar(args[1])?.to_u32()?;
815
816                 if len > 0 {
817                     let data = gen_random(this, len as usize)?;
818                     this.memory_mut().get_mut(ptr.alloc_id)?
819                         .write_bytes(tcx, ptr, &data)?;
820                 }
821
822                 this.write_scalar(Scalar::from_bool(true), dest)?;
823             }
824
825             // We can't execute anything else.
826             _ => {
827                 return err!(Unimplemented(
828                     format!("can't call foreign function: {}", link_name),
829                 ));
830             }
831         }
832
833         this.goto_block(Some(ret))?;
834         this.dump_place(*dest);
835         Ok(())
836     }
837
838     fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> EvalResult<'tcx> {
839         self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
840     }
841
842     /// Evaluates the scalar at the specified path. Returns Some(val)
843     /// if the path could be resolved, and None otherwise
844     fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {
845         let this = self.eval_context_mut();
846         if let Ok(instance) = this.resolve_path(path) {
847             let cid = GlobalId {
848                 instance,
849                 promoted: None,
850             };
851             let const_val = this.const_eval_raw(cid)?;
852             let const_val = this.read_scalar(const_val.into())?;
853             return Ok(Some(const_val));
854         }
855         return Ok(None);
856     }
857 }
858
859 fn gen_random<'a, 'mir, 'tcx>(
860     this: &mut MiriEvalContext<'a, 'mir, 'tcx>,
861     len: usize,
862 ) -> Result<Vec<u8>, EvalError<'tcx>>  {
863
864     match &mut this.machine.rng {
865         Some(rng) => {
866             let mut data = vec![0; len];
867             rng.fill_bytes(&mut data);
868             Ok(data)
869         }
870         None => {
871             err!(Unimplemented(
872                 "miri does not support gathering system entropy in deterministic mode!
873                 Use '-Zmiri-seed=<seed>' to enable random number generation.
874                 WARNING: Miri does *not* generate cryptographically secure entropy -
875                 do not use Miri to run any program that needs secure random number generation".to_owned(),
876             ))
877         }
878     }
879 }