]> git.lizzy.rs Git - rust.git/blob - src/fn_call.rs
Partial rustup
[rust.git] / src / fn_call.rs
1 use rustc::ty::{self, Ty};
2 use rustc::ty::layout::{self, Align, LayoutOf, Size};
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_scalar(discr_dest, Scalar::from_u128(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_scalar(niche_dest, Scalar::from_u128(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_scalar(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::from_bytes(size), align, Some(MemoryKind::C.into()))?;
191                     self.write_scalar(dest, Scalar::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_scalar(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 = Size::from_bytes(self.value_to_scalar(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_scalar(
299                     dest,
300                     Scalar::from_i8(result),
301                     dest_ty,
302                 )?;
303             }
304
305             "memrchr" => {
306                 let ptr = self.into_ptr(args[0].value)?;
307                 let val = self.value_to_scalar(args[1])?.to_u64()? as u8;
308                 let num = self.value_to_scalar(args[2])?.to_u64()?;
309                 if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position(
310                     |&c| c == val,
311                 )
312                 {
313                     let new_ptr = ptr.ptr_offset(Size::from_bytes(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_scalar(args[1])?.to_u64()? as u8;
323                 let num = self.value_to_scalar(args[2])?.to_u64()?;
324                 if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position(
325                     |&c| c == val,
326                 )
327                 {
328                     let new_ptr = ptr.ptr_offset(Size::from_bytes(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) => Scalar::Ptr(var),
341                         None => Scalar::null(),
342                     }
343                 };
344                 self.write_scalar(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_scalar(dest, Scalar::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                         Size::from_bytes((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(Size::from_bytes(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_scalar(dest, Scalar::from_i128(-1), dest_ty)?;
401                 }
402             }
403
404             "write" => {
405                 let fd = self.value_to_scalar(args[0])?.to_u64()?;
406                 let buf = self.into_ptr(args[1].value)?;
407                 let n = self.value_to_scalar(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, Size::from_bytes(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 i64,
421                         Err(_) => -1,
422                     }
423                 } else {
424                     warn!("Ignored output to FD {}", fd);
425                     n as i64 // pretend it all went well
426                 }; // now result is the value we return back to the program
427                 let ptr_size = self.memory.pointer_size();
428                 self.write_scalar(
429                     dest,
430                     Scalar::from_isize(result, ptr_size),
431                     dest_ty,
432                 )?;
433             }
434
435             "strlen" => {
436                 let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
437                 let n = self.memory.read_c_str(ptr)?.len();
438                 let ptr_size = self.memory.pointer_size();
439                 self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?;
440             }
441
442             // Some things needed for sys::thread initialization to go through
443             "signal" | "sigaction" | "sigaltstack" => {
444                 self.write_scalar(dest, Scalar::null(), dest_ty)?;
445             }
446
447             "sysconf" => {
448                 let name = self.value_to_scalar(args[0])?.to_u64()?;
449
450                 trace!("sysconf() called with name {}", name);
451                 // cache the sysconf integers via miri's global cache
452                 let paths = &[
453                     (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)),
454                     (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)),
455                 ];
456                 let mut result = None;
457                 for &(path, path_value) in paths {
458                     if let Ok(instance) = self.resolve_path(path) {
459                         let cid = GlobalId {
460                             instance,
461                             promoted: None,
462                         };
463                         let const_val = self.const_eval(cid)?;
464                         let value = const_val.unwrap_usize(self.tcx.tcx);
465                         if value == name {
466                             result = Some(path_value);
467                             break;
468                         }
469                     }
470                 }
471                 if let Some(result) = result {
472                     self.write_scalar(dest, result, dest_ty)?;
473                 } else {
474                     return err!(Unimplemented(
475                         format!("Unimplemented sysconf name: {}", name),
476                     ));
477                 }
478             }
479
480             // Hook pthread calls that go to the thread-local storage memory subsystem
481             "pthread_key_create" => {
482                 let key_ptr = self.into_ptr(args[0].value)?;
483                 let key_align = self.layout_of(args[0].ty)?.align;
484
485                 // Extract the function type out of the signature (that seems easier than constructing it ourselves...)
486                 let dtor = match self.into_ptr(args[1].value)? {
487                     Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?),
488                     Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes),
489                     Scalar::Bits { bits: 0, .. } => None,
490                     Scalar::Bits { .. } => return err!(ReadBytesAsPointer),
491                 };
492
493                 // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
494                 let key_type = args[0].ty.builtin_deref(true)
495                                    .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
496                 let key_size = self.layout_of(key_type)?.size;
497
498                 // Create key and write it into the memory where key_ptr wants it
499                 let key = self.memory.create_tls_key(dtor) as u128;
500                 if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) {
501                     return err!(OutOfTls);
502                 }
503                 self.memory.write_scalar(
504                     key_ptr,
505                     key_align,
506                     Scalar::from_u128(key),
507                     key_size,
508                     false,
509                 )?;
510
511                 // Return success (0)
512                 self.write_null(dest, dest_ty)?;
513             }
514             "pthread_key_delete" => {
515                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
516                 let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey;
517                 self.memory.delete_tls_key(key)?;
518                 // Return success (0)
519                 self.write_null(dest, dest_ty)?;
520             }
521             "pthread_getspecific" => {
522                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
523                 let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey;
524                 let ptr = self.memory.load_tls(key)?;
525                 self.write_ptr(dest, ptr, dest_ty)?;
526             }
527             "pthread_setspecific" => {
528                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
529                 let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey;
530                 let new_ptr = self.into_ptr(args[1].value)?;
531                 self.memory.store_tls(key, new_ptr)?;
532
533                 // Return success (0)
534                 self.write_null(dest, dest_ty)?;
535             }
536
537             "_tlv_atexit" => {
538                 return err!(Unimplemented("can't interpret with full mir for osx target".to_owned()));
539             },
540
541             // Stub out all the other pthread calls to just return 0
542             link_name if link_name.starts_with("pthread_") => {
543                 info!("ignoring C ABI call: {}", link_name);
544                 self.write_null(dest, dest_ty)?;
545             }
546
547             "mmap" => {
548                 // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value
549                 let addr = self.into_ptr(args[0].value)?;
550                 self.write_ptr(dest, addr, dest_ty)?;
551             }
552
553             _ => {
554                 return err!(Unimplemented(
555                     format!("can't call C ABI function: {}", link_name),
556                 ));
557             }
558         }
559
560         // Since we pushed no stack frame, the main loop will act
561         // as if the call just completed and it's returning to the
562         // current frame.
563         self.dump_local(dest);
564         self.goto_block(dest_block);
565         Ok(())
566     }
567
568     /// Get an instance for a path.
569     fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> {
570         self.tcx
571             .crates()
572             .iter()
573             .find(|&&krate| self.tcx.original_crate_name(krate) == path[0])
574             .and_then(|krate| {
575                 let krate = DefId {
576                     krate: *krate,
577                     index: CRATE_DEF_INDEX,
578                 };
579                 let mut items = self.tcx.item_children(krate);
580                 let mut path_it = path.iter().skip(1).peekable();
581
582                 while let Some(segment) = path_it.next() {
583                     for item in mem::replace(&mut items, Default::default()).iter() {
584                         if item.ident.name == *segment {
585                             if path_it.peek().is_none() {
586                                 return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id()));
587                             }
588
589                             items = self.tcx.item_children(item.def.def_id());
590                             break;
591                         }
592                     }
593                 }
594                 None
595             })
596             .ok_or_else(|| {
597                 let path = path.iter().map(|&s| s.to_owned()).collect();
598                 EvalErrorKind::PathNotFound(path).into()
599             })
600     }
601
602     fn call_missing_fn(
603         &mut self,
604         instance: ty::Instance<'tcx>,
605         destination: Option<(Place, mir::BasicBlock)>,
606         args: &[ValTy<'tcx>],
607         sig: ty::FnSig<'tcx>,
608         path: String,
609     ) -> EvalResult<'tcx> {
610         // In some cases in non-MIR libstd-mode, not having a destination is legit.  Handle these early.
611         match &path[..] {
612             "std::panicking::rust_panic_with_hook" |
613             "core::panicking::panic_fmt::::panic_impl" |
614             "std::rt::begin_panic_fmt" => return err!(Panic),
615             _ => {}
616         }
617
618         let dest_ty = sig.output();
619         let (dest, dest_block) = destination.ok_or_else(
620             || EvalErrorKind::NoMirFor(path.clone()),
621         )?;
622
623         if sig.abi == Abi::C {
624             // An external C function
625             // TODO: That functions actually has a similar preamble to what follows here.  May make sense to
626             // unify these two mechanisms for "hooking into missing functions".
627             self.call_c_abi(
628                 instance.def_id(),
629                 args,
630                 dest,
631                 dest_ty,
632                 dest_block,
633             )?;
634             return Ok(());
635         }
636
637         match &path[..] {
638             // Allocators are magic.  They have no MIR, even when the rest of libstd does.
639             "alloc::alloc::::__rust_alloc" => {
640                 let size = self.value_to_scalar(args[0])?.to_u64()?;
641                 let align = self.value_to_scalar(args[1])?.to_u64()?;
642                 if size == 0 {
643                     return err!(HeapAllocZeroBytes);
644                 }
645                 if !align.is_power_of_two() {
646                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
647                 }
648                 let ptr = self.memory.allocate(Size::from_bytes(size),
649                                                Align::from_bytes(align, align).unwrap(),
650                                                Some(MemoryKind::Rust.into()))?;
651                 self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?;
652             }
653             "alloc::alloc::::__rust_alloc_zeroed" => {
654                 let size = self.value_to_scalar(args[0])?.to_u64()?;
655                 let align = self.value_to_scalar(args[1])?.to_u64()?;
656                 if size == 0 {
657                     return err!(HeapAllocZeroBytes);
658                 }
659                 if !align.is_power_of_two() {
660                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
661                 }
662                 let ptr = self.memory.allocate(Size::from_bytes(size),
663                                                Align::from_bytes(align, align).unwrap(),
664                                                Some(MemoryKind::Rust.into()))?;
665                 self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?;
666                 self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?;
667             }
668             "alloc::alloc::::__rust_dealloc" => {
669                 let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
670                 let old_size = self.value_to_scalar(args[1])?.to_u64()?;
671                 let align = self.value_to_scalar(args[2])?.to_u64()?;
672                 if old_size == 0 {
673                     return err!(HeapAllocZeroBytes);
674                 }
675                 if !align.is_power_of_two() {
676                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
677                 }
678                 self.memory.deallocate(
679                     ptr,
680                     Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())),
681                     MemoryKind::Rust.into(),
682                 )?;
683             }
684             "alloc::alloc::::__rust_realloc" => {
685                 let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
686                 let old_size = self.value_to_scalar(args[1])?.to_u64()?;
687                 let align = self.value_to_scalar(args[2])?.to_u64()?;
688                 let new_size = self.value_to_scalar(args[3])?.to_u64()?;
689                 if old_size == 0 || new_size == 0 {
690                     return err!(HeapAllocZeroBytes);
691                 }
692                 if !align.is_power_of_two() {
693                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
694                 }
695                 let new_ptr = self.memory.reallocate(
696                     ptr,
697                     Size::from_bytes(old_size),
698                     Align::from_bytes(align, align).unwrap(),
699                     Size::from_bytes(new_size),
700                     Align::from_bytes(align, align).unwrap(),
701                     MemoryKind::Rust.into(),
702                 )?;
703                 self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?;
704             }
705
706             // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
707             // Still, we can make many things mostly work by "emulating" or ignoring some functions.
708             "std::io::_print" => {
709                 warn!(
710                     "Ignoring output.  To run programs that print, make sure you have a libstd with full MIR."
711                 );
712             }
713             "std::thread::Builder::new" => {
714                 return err!(Unimplemented("miri does not support threading".to_owned()))
715             }
716             "std::env::args" => {
717                 return err!(Unimplemented(
718                     "miri does not support program arguments".to_owned(),
719                 ))
720             }
721             "std::panicking::panicking" |
722             "std::rt::panicking" => {
723                 // we abort on panic -> `std::rt::panicking` always returns false
724                 let bool = self.tcx.types.bool;
725                 self.write_scalar(dest, Scalar::from_bool(false), bool)?;
726             }
727             "std::sys::imp::c::::AddVectoredExceptionHandler" |
728             "std::sys::imp::c::::SetThreadStackGuarantee" => {
729                 let usize = self.tcx.types.usize;
730                 // any non zero value works for the stdlib. This is just used for stackoverflows anyway
731                 self.write_scalar(dest, Scalar::from_u128(1), usize)?;
732             },
733             _ => return err!(NoMirFor(path)),
734         }
735
736         // Since we pushed no stack frame, the main loop will act
737         // as if the call just completed and it's returning to the
738         // current frame.
739         self.dump_local(dest);
740         self.goto_block(dest_block);
741         return Ok(());
742     }
743
744     fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
745         self.write_scalar(dest, Scalar::null(), dest_ty)
746     }
747 }