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