]> git.lizzy.rs Git - rust.git/blob - src/fn_call.rs
Move back to a normal folder structure
[rust.git] / src / fn_call.rs
1 use rustc::ty::{self, Ty};
2 use rustc::ty::layout::{self, Align, LayoutOf};
3 use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
4 use rustc::mir;
5 use rustc_data_structures::indexed_vec::Idx;
6 use rustc_target::spec::abi::Abi;
7 use syntax::attr;
8 use syntax::codemap::Span;
9
10 use std::mem;
11
12 use super::*;
13
14 use tls::MemoryExt;
15
16 use super::memory::MemoryKind;
17
18 fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>(
19         ecx: &mut EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>>,
20         dest_ty: Ty<'tcx>,
21         dest: Place,
22         variant_index: usize,
23     ) -> EvalResult<'tcx> {
24         let layout = ecx.layout_of(dest_ty)?;
25
26         match layout.variants {
27             layout::Variants::Single { index } => {
28                 if index != variant_index {
29                     // If the layout of an enum is `Single`, all
30                     // other variants are necessarily uninhabited.
31                     assert_eq!(layout.for_variant(&ecx, variant_index).abi,
32                                layout::Abi::Uninhabited);
33                 }
34             }
35             layout::Variants::Tagged { .. } => {
36                 let discr_val = dest_ty.ty_adt_def().unwrap()
37                     .discriminant_for_variant(*ecx.tcx, variant_index)
38                     .val;
39
40                 let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?;
41                 ecx.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?;
42             }
43             layout::Variants::NicheFilling {
44                 dataful_variant,
45                 ref niche_variants,
46                 niche_start,
47                 ..
48             } => {
49                 if variant_index != dataful_variant {
50                     let (niche_dest, niche) =
51                         ecx.place_field(dest, mir::Field::new(0), layout)?;
52                     let niche_value = ((variant_index - niche_variants.start()) as u128)
53                         .wrapping_add(niche_start);
54                     ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?;
55                 }
56             }
57         }
58
59         Ok(())
60     }
61
62 pub trait EvalContextExt<'tcx> {
63     fn call_c_abi(
64         &mut self,
65         def_id: DefId,
66         args: &[ValTy<'tcx>],
67         dest: Place,
68         dest_ty: Ty<'tcx>,
69         dest_block: mir::BasicBlock,
70     ) -> EvalResult<'tcx>;
71
72     fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>;
73
74     fn call_missing_fn(
75         &mut self,
76         instance: ty::Instance<'tcx>,
77         destination: Option<(Place, mir::BasicBlock)>,
78         args: &[ValTy<'tcx>],
79         sig: ty::FnSig<'tcx>,
80         path: String,
81     ) -> EvalResult<'tcx>;
82
83     fn eval_fn_call(
84         &mut self,
85         instance: ty::Instance<'tcx>,
86         destination: Option<(Place, mir::BasicBlock)>,
87         args: &[ValTy<'tcx>],
88         span: Span,
89         sig: ty::FnSig<'tcx>,
90     ) -> EvalResult<'tcx, bool>;
91
92     fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>;
93 }
94
95 impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
96     fn eval_fn_call(
97         &mut self,
98         instance: ty::Instance<'tcx>,
99         destination: Option<(Place, mir::BasicBlock)>,
100         args: &[ValTy<'tcx>],
101         span: Span,
102         sig: ty::FnSig<'tcx>,
103     ) -> EvalResult<'tcx, bool> {
104         trace!("eval_fn_call: {:#?}, {:#?}", instance, destination);
105
106         let def_id = instance.def_id();
107         let item_path = self.tcx.absolute_item_path_str(def_id);
108         if item_path.starts_with("std::") {
109             //println!("{}", item_path);
110         }
111         match &*item_path {
112             "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => {
113                 // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself.
114                 let ret_ty = sig.output();
115                 match ret_ty.sty {
116                     ty::TyAdt(ref adt_def, _) => {
117                         assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path);
118                         let none_variant_index = adt_def.variants.iter().position(|def| {
119                             def.name.as_str() == "None"
120                         }).expect("No None variant");
121                         let (return_place, return_to_block) = destination.unwrap();
122                         write_discriminant_value(self, ret_ty, return_place, none_variant_index)?;
123                         self.goto_block(return_to_block);
124                         return Ok(true);
125                     }
126                     _ => panic!("Unexpected return type for {}", item_path)
127                 }
128             }
129             "std::sys::unix::fast_thread_local::register_dtor" => {
130                 // TODO: register the dtor
131                 let (_return_place, return_to_block) = destination.unwrap();
132                 self.goto_block(return_to_block);
133                 return Ok(true);
134             }
135             _ => {}
136         }
137
138         let mir = match self.load_mir(instance.def) {
139             Ok(mir) => mir,
140             Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
141                 self.call_missing_fn(
142                     instance,
143                     destination,
144                     args,
145                     sig,
146                     path,
147                 )?;
148                 return Ok(true);
149             }
150             Err(other) => return Err(other),
151         };
152
153         let (return_place, return_to_block) = match destination {
154             Some((place, block)) => (place, StackPopCleanup::Goto(block)),
155             None => (Place::undef(), StackPopCleanup::None),
156         };
157
158         self.push_stack_frame(
159             instance,
160             span,
161             mir,
162             return_place,
163             return_to_block,
164         )?;
165
166         Ok(false)
167     }
168
169     fn call_c_abi(
170         &mut self,
171         def_id: DefId,
172         args: &[ValTy<'tcx>],
173         dest: Place,
174         dest_ty: Ty<'tcx>,
175         dest_block: mir::BasicBlock,
176     ) -> EvalResult<'tcx> {
177         let attrs = self.tcx.get_attrs(def_id);
178         let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
179             Some(name) => name.as_str(),
180             None => self.tcx.item_name(def_id).as_str(),
181         };
182
183         match &link_name[..] {
184             "malloc" => {
185                 let size = self.value_to_primval(args[0])?.to_u64()?;
186                 if size == 0 {
187                     self.write_null(dest, dest_ty)?;
188                 } else {
189                     let align = self.tcx.data_layout.pointer_align;
190                     let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?;
191                     self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
192                 }
193             }
194
195             "free" => {
196                 let ptr = self.into_ptr(args[0].value)?;
197                 if !ptr.is_null()? {
198                     self.memory.deallocate(
199                         ptr.to_ptr()?,
200                         None,
201                         MemoryKind::C.into(),
202                     )?;
203                 }
204             }
205
206             "syscall" => {
207                 // TODO: read `syscall` ids like `sysconf` ids and
208                 // figure out some way to actually process some of them
209                 //
210                 // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
211                 // is called if a `HashMap` is created the regular way.
212                 match self.value_to_primval(args[0])?.to_u64()? {
213                     318 | 511 => {
214                         return err!(Unimplemented(
215                             "miri does not support random number generators".to_owned(),
216                         ))
217                     }
218                     id => {
219                         return err!(Unimplemented(
220                             format!("miri does not support syscall id {}", id),
221                         ))
222                     }
223                 }
224             }
225
226             "dlsym" => {
227                 let _handle = self.into_ptr(args[0].value)?;
228                 let symbol = self.into_ptr(args[1].value)?.to_ptr()?;
229                 let symbol_name = self.memory.read_c_str(symbol)?;
230                 let err = format!("bad c unicode symbol: {:?}", symbol_name);
231                 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
232                 return err!(Unimplemented(format!(
233                     "miri does not support dynamically loading libraries (requested symbol: {})",
234                     symbol_name
235                 )));
236             }
237
238             "__rust_maybe_catch_panic" => {
239                 // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
240                 // We abort on panic, so not much is going on here, but we still have to call the closure
241                 let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
242                 let f = self.into_ptr(args[0].value)?.to_ptr()?;
243                 let data = self.into_ptr(args[1].value)?;
244                 let f_instance = self.memory.get_fn(f)?;
245                 self.write_null(dest, dest_ty)?;
246
247                 // Now we make a function call.  TODO: Consider making this re-usable?  EvalContext::step does sth. similar for the TLS dtors,
248                 // and of course eval_main.
249                 let mir = self.load_mir(f_instance.def)?;
250                 self.push_stack_frame(
251                     f_instance,
252                     mir.span,
253                     mir,
254                     Place::undef(),
255                     StackPopCleanup::Goto(dest_block),
256                 )?;
257                 let mut args = self.frame().mir.args_iter();
258
259                 let arg_local = args.next().ok_or(
260                     EvalErrorKind::AbiViolation(
261                         "Argument to __rust_maybe_catch_panic does not take enough arguments."
262                             .to_owned(),
263                     ),
264                 )?;
265                 let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?;
266                 self.write_ptr(arg_dest, data, u8_ptr_ty)?;
267
268                 assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
269
270                 // We ourselves return 0
271                 self.write_null(dest, dest_ty)?;
272
273                 // Don't fall through
274                 return Ok(());
275             }
276
277             "__rust_start_panic" => {
278                 return err!(Panic);
279             }
280
281             "memcmp" => {
282                 let left = self.into_ptr(args[0].value)?;
283                 let right = self.into_ptr(args[1].value)?;
284                 let n = self.value_to_primval(args[2])?.to_u64()?;
285
286                 let result = {
287                     let left_bytes = self.memory.read_bytes(left, n)?;
288                     let right_bytes = self.memory.read_bytes(right, n)?;
289
290                     use std::cmp::Ordering::*;
291                     match left_bytes.cmp(right_bytes) {
292                         Less => -1i8,
293                         Equal => 0,
294                         Greater => 1,
295                     }
296                 };
297
298                 self.write_primval(
299                     dest,
300                     PrimVal::Bytes(result as u128),
301                     dest_ty,
302                 )?;
303             }
304
305             "memrchr" => {
306                 let ptr = self.into_ptr(args[0].value)?;
307                 let val = self.value_to_primval(args[1])?.to_u64()? as u8;
308                 let num = self.value_to_primval(args[2])?.to_u64()?;
309                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(
310                     |&c| c == val,
311                 )
312                 {
313                     let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?;
314                     self.write_ptr(dest, new_ptr, dest_ty)?;
315                 } else {
316                     self.write_null(dest, dest_ty)?;
317                 }
318             }
319
320             "memchr" => {
321                 let ptr = self.into_ptr(args[0].value)?;
322                 let val = self.value_to_primval(args[1])?.to_u64()? as u8;
323                 let num = self.value_to_primval(args[2])?.to_u64()?;
324                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(
325                     |&c| c == val,
326                 )
327                 {
328                     let new_ptr = ptr.offset(idx as u64, &self)?;
329                     self.write_ptr(dest, new_ptr, dest_ty)?;
330                 } else {
331                     self.write_null(dest, dest_ty)?;
332                 }
333             }
334
335             "getenv" => {
336                 let result = {
337                     let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?;
338                     let name = self.memory.read_c_str(name_ptr)?;
339                     match self.machine.env_vars.get(name) {
340                         Some(&var) => PrimVal::Ptr(var),
341                         None => PrimVal::Bytes(0),
342                     }
343                 };
344                 self.write_primval(dest, result, dest_ty)?;
345             }
346
347             "unsetenv" => {
348                 let mut success = None;
349                 {
350                     let name_ptr = self.into_ptr(args[0].value)?;
351                     if !name_ptr.is_null()? {
352                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
353                         if !name.is_empty() && !name.contains(&b'=') {
354                             success = Some(self.machine.env_vars.remove(name));
355                         }
356                     }
357                 }
358                 if let Some(old) = success {
359                     if let Some(var) = old {
360                         self.memory.deallocate(var, None, MemoryKind::Env.into())?;
361                     }
362                     self.write_null(dest, dest_ty)?;
363                 } else {
364                     self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
365                 }
366             }
367
368             "setenv" => {
369                 let mut new = None;
370                 {
371                     let name_ptr = self.into_ptr(args[0].value)?;
372                     let value_ptr = self.into_ptr(args[1].value)?.to_ptr()?;
373                     let value = self.memory.read_c_str(value_ptr)?;
374                     if !name_ptr.is_null()? {
375                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
376                         if !name.is_empty() && !name.contains(&b'=') {
377                             new = Some((name.to_owned(), value.to_owned()));
378                         }
379                     }
380                 }
381                 if let Some((name, value)) = new {
382                     // +1 for the null terminator
383                     let value_copy = self.memory.allocate(
384                         (value.len() + 1) as u64,
385                         Align::from_bytes(1, 1).unwrap(),
386                         Some(MemoryKind::Env.into()),
387                     )?;
388                     self.memory.write_bytes(value_copy.into(), &value)?;
389                     let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into();
390                     self.memory.write_bytes(trailing_zero_ptr, &[0])?;
391                     if let Some(var) = self.machine.env_vars.insert(
392                         name.to_owned(),
393                         value_copy,
394                     )
395                     {
396                         self.memory.deallocate(var, None, MemoryKind::Env.into())?;
397                     }
398                     self.write_null(dest, dest_ty)?;
399                 } else {
400                     self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
401                 }
402             }
403
404             "write" => {
405                 let fd = self.value_to_primval(args[0])?.to_u64()?;
406                 let buf = self.into_ptr(args[1].value)?;
407                 let n = self.value_to_primval(args[2])?.to_u64()?;
408                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
409                 let result = if fd == 1 || fd == 2 {
410                     // stdout/stderr
411                     use std::io::{self, Write};
412
413                     let buf_cont = self.memory.read_bytes(buf, n)?;
414                     let res = if fd == 1 {
415                         io::stdout().write(buf_cont)
416                     } else {
417                         io::stderr().write(buf_cont)
418                     };
419                     match res {
420                         Ok(n) => n as isize,
421                         Err(_) => -1,
422                     }
423                 } else {
424                     warn!("Ignored output to FD {}", fd);
425                     n as isize // pretend it all went well
426                 }; // now result is the value we return back to the program
427                 self.write_primval(
428                     dest,
429                     PrimVal::Bytes(result as u128),
430                     dest_ty,
431                 )?;
432             }
433
434             "strlen" => {
435                 let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
436                 let n = self.memory.read_c_str(ptr)?.len();
437                 self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
438             }
439
440             // Some things needed for sys::thread initialization to go through
441             "signal" | "sigaction" | "sigaltstack" => {
442                 self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
443             }
444
445             "sysconf" => {
446                 let name = self.value_to_primval(args[0])?.to_u64()?;
447
448                 trace!("sysconf() called with name {}", name);
449                 // cache the sysconf integers via miri's global cache
450                 let paths = &[
451                     (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)),
452                     (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)),
453                 ];
454                 let mut result = None;
455                 for &(path, path_value) in paths {
456                     if let Ok(instance) = self.resolve_path(path) {
457                         let cid = GlobalId {
458                             instance,
459                             promoted: None,
460                         };
461                         let const_val = self.const_eval(cid)?;
462                         let value = const_val.val.unwrap_u64();
463                         if value == name {
464                             result = Some(path_value);
465                             break;
466                         }
467                     }
468                 }
469                 if let Some(result) = result {
470                     self.write_primval(dest, result, dest_ty)?;
471                 } else {
472                     return err!(Unimplemented(
473                         format!("Unimplemented sysconf name: {}", name),
474                     ));
475                 }
476             }
477
478             // Hook pthread calls that go to the thread-local storage memory subsystem
479             "pthread_key_create" => {
480                 let key_ptr = self.into_ptr(args[0].value)?;
481                 let key_align = self.layout_of(args[0].ty)?.align;
482
483                 // Extract the function type out of the signature (that seems easier than constructing it ourselves...)
484                 let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() {
485                     PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?),
486                     PrimVal::Bytes(0) => None,
487                     PrimVal::Bytes(_) => return err!(ReadBytesAsPointer),
488                     PrimVal::Undef => return err!(ReadUndefBytes),
489                 };
490
491                 // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
492                 let key_type = args[0].ty.builtin_deref(true)
493                                    .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
494                 let key_size = self.layout_of(key_type)?.size;
495
496                 // Create key and write it into the memory where key_ptr wants it
497                 let key = self.memory.create_tls_key(dtor) as u128;
498                 if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) {
499                     return err!(OutOfTls);
500                 }
501                 self.memory.write_primval(
502                     key_ptr,
503                     key_align,
504                     PrimVal::Bytes(key),
505                     key_size.bytes(),
506                     false,
507                 )?;
508
509                 // Return success (0)
510                 self.write_null(dest, dest_ty)?;
511             }
512             "pthread_key_delete" => {
513                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
514                 let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey;
515                 self.memory.delete_tls_key(key)?;
516                 // Return success (0)
517                 self.write_null(dest, dest_ty)?;
518             }
519             "pthread_getspecific" => {
520                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
521                 let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey;
522                 let ptr = self.memory.load_tls(key)?;
523                 self.write_ptr(dest, ptr, dest_ty)?;
524             }
525             "pthread_setspecific" => {
526                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
527                 let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey;
528                 let new_ptr = self.into_ptr(args[1].value)?;
529                 self.memory.store_tls(key, new_ptr)?;
530
531                 // Return success (0)
532                 self.write_null(dest, dest_ty)?;
533             }
534             "_tlv_atexit" => {
535                 // TODO: handle it
536             }
537
538             // Stub out all the other pthread calls to just return 0
539             link_name if link_name.starts_with("pthread_") => {
540                 info!("ignoring C ABI call: {}", link_name);
541                 self.write_null(dest, dest_ty)?;
542             }
543
544             _ => {
545                 return err!(Unimplemented(
546                     format!("can't call C ABI function: {}", link_name),
547                 ));
548             }
549         }
550
551         // Since we pushed no stack frame, the main loop will act
552         // as if the call just completed and it's returning to the
553         // current frame.
554         self.dump_local(dest);
555         self.goto_block(dest_block);
556         Ok(())
557     }
558
559     /// Get an instance for a path.
560     fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> {
561         self.tcx
562             .crates()
563             .iter()
564             .find(|&&krate| self.tcx.original_crate_name(krate) == path[0])
565             .and_then(|krate| {
566                 let krate = DefId {
567                     krate: *krate,
568                     index: CRATE_DEF_INDEX,
569                 };
570                 let mut items = self.tcx.item_children(krate);
571                 let mut path_it = path.iter().skip(1).peekable();
572
573                 while let Some(segment) = path_it.next() {
574                     for item in mem::replace(&mut items, Default::default()).iter() {
575                         if item.ident.name == *segment {
576                             if path_it.peek().is_none() {
577                                 return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id()));
578                             }
579
580                             items = self.tcx.item_children(item.def.def_id());
581                             break;
582                         }
583                     }
584                 }
585                 None
586             })
587             .ok_or_else(|| {
588                 let path = path.iter().map(|&s| s.to_owned()).collect();
589                 EvalErrorKind::PathNotFound(path).into()
590             })
591     }
592
593     fn call_missing_fn(
594         &mut self,
595         instance: ty::Instance<'tcx>,
596         destination: Option<(Place, mir::BasicBlock)>,
597         args: &[ValTy<'tcx>],
598         sig: ty::FnSig<'tcx>,
599         path: String,
600     ) -> EvalResult<'tcx> {
601         // In some cases in non-MIR libstd-mode, not having a destination is legit.  Handle these early.
602         match &path[..] {
603             "std::panicking::rust_panic_with_hook" |
604             "core::panicking::panic_fmt::::panic_impl" |
605             "std::rt::begin_panic_fmt" => return err!(Panic),
606             _ => {}
607         }
608
609         let dest_ty = sig.output();
610         let (dest, dest_block) = destination.ok_or_else(
611             || EvalErrorKind::NoMirFor(path.clone()),
612         )?;
613
614         if sig.abi == Abi::C {
615             // An external C function
616             // TODO: That functions actually has a similar preamble to what follows here.  May make sense to
617             // unify these two mechanisms for "hooking into missing functions".
618             self.call_c_abi(
619                 instance.def_id(),
620                 args,
621                 dest,
622                 dest_ty,
623                 dest_block,
624             )?;
625             return Ok(());
626         }
627
628         match &path[..] {
629             // Allocators are magic.  They have no MIR, even when the rest of libstd does.
630             "alloc::alloc::::__rust_alloc" => {
631                 let size = self.value_to_primval(args[0])?.to_u64()?;
632                 let align = self.value_to_primval(args[1])?.to_u64()?;
633                 if size == 0 {
634                     return err!(HeapAllocZeroBytes);
635                 }
636                 if !align.is_power_of_two() {
637                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
638                 }
639                 let ptr = self.memory.allocate(size,
640                                                Align::from_bytes(align, align).unwrap(),
641                                                Some(MemoryKind::Rust.into()))?;
642                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
643             }
644             "alloc::alloc::::__rust_alloc_zeroed" => {
645                 let size = self.value_to_primval(args[0])?.to_u64()?;
646                 let align = self.value_to_primval(args[1])?.to_u64()?;
647                 if size == 0 {
648                     return err!(HeapAllocZeroBytes);
649                 }
650                 if !align.is_power_of_two() {
651                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
652                 }
653                 let ptr = self.memory.allocate(size,
654                                                Align::from_bytes(align, align).unwrap(),
655                                                Some(MemoryKind::Rust.into()))?;
656                 self.memory.write_repeat(ptr.into(), 0, size)?;
657                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
658             }
659             "alloc::alloc::::__rust_dealloc" => {
660                 let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
661                 let old_size = self.value_to_primval(args[1])?.to_u64()?;
662                 let align = self.value_to_primval(args[2])?.to_u64()?;
663                 if old_size == 0 {
664                     return err!(HeapAllocZeroBytes);
665                 }
666                 if !align.is_power_of_two() {
667                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
668                 }
669                 self.memory.deallocate(
670                     ptr,
671                     Some((old_size, Align::from_bytes(align, align).unwrap())),
672                     MemoryKind::Rust.into(),
673                 )?;
674             }
675             "alloc::alloc::::__rust_realloc" => {
676                 let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
677                 let old_size = self.value_to_primval(args[1])?.to_u64()?;
678                 let align = self.value_to_primval(args[2])?.to_u64()?;
679                 let new_size = self.value_to_primval(args[3])?.to_u64()?;
680                 if old_size == 0 || new_size == 0 {
681                     return err!(HeapAllocZeroBytes);
682                 }
683                 if !align.is_power_of_two() {
684                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
685                 }
686                 let new_ptr = self.memory.reallocate(
687                     ptr,
688                     old_size,
689                     Align::from_bytes(align, align).unwrap(),
690                     new_size,
691                     Align::from_bytes(align, align).unwrap(),
692                     MemoryKind::Rust.into(),
693                 )?;
694                 self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
695             }
696
697             // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
698             // Still, we can make many things mostly work by "emulating" or ignoring some functions.
699             "std::io::_print" => {
700                 warn!(
701                     "Ignoring output.  To run programs that print, make sure you have a libstd with full MIR."
702                 );
703             }
704             "std::thread::Builder::new" => {
705                 return err!(Unimplemented("miri does not support threading".to_owned()))
706             }
707             "std::env::args" => {
708                 return err!(Unimplemented(
709                     "miri does not support program arguments".to_owned(),
710                 ))
711             }
712             "std::panicking::panicking" |
713             "std::rt::panicking" => {
714                 // we abort on panic -> `std::rt::panicking` always returns false
715                 let bool = self.tcx.types.bool;
716                 self.write_primval(dest, PrimVal::from_bool(false), bool)?;
717             }
718             "std::sys::imp::c::::AddVectoredExceptionHandler" |
719             "std::sys::imp::c::::SetThreadStackGuarantee" => {
720                 let usize = self.tcx.types.usize;
721                 // any non zero value works for the stdlib. This is just used for stackoverflows anyway
722                 self.write_primval(dest, PrimVal::Bytes(1), usize)?;
723             },
724             _ => return err!(NoMirFor(path)),
725         }
726
727         // Since we pushed no stack frame, the main loop will act
728         // as if the call just completed and it's returning to the
729         // current frame.
730         self.dump_local(dest);
731         self.goto_block(dest_block);
732         return Ok(());
733     }
734
735     fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
736         self.write_primval(dest, PrimVal::Bytes(0), dest_ty)
737     }
738 }