]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/terminator/mod.rs
we need to normalize associated types also deep in the hierarchy (89)
[rust.git] / src / librustc_mir / interpret / terminator / mod.rs
1 use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
2 use rustc::mir;
3 use rustc::ty::{self, TypeVariants, Ty};
4 use rustc::ty::layout::Layout;
5 use syntax::codemap::Span;
6 use syntax::attr;
7 use syntax::abi::Abi;
8
9 use error::{EvalError, EvalResult};
10 use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited, self};
11 use lvalue::Lvalue;
12 use memory::{MemoryPointer, TlsKey, Kind};
13 use value::{PrimVal, Value};
14 use rustc_data_structures::indexed_vec::Idx;
15 use const_eval;
16
17 use std::mem;
18
19 mod drop;
20 mod intrinsic;
21
22 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
23     pub(super) fn goto_block(&mut self, target: mir::BasicBlock) {
24         self.frame_mut().block = target;
25         self.frame_mut().stmt = 0;
26     }
27
28     pub(super) fn eval_terminator(
29         &mut self,
30         terminator: &mir::Terminator<'tcx>,
31     ) -> EvalResult<'tcx> {
32         use rustc::mir::TerminatorKind::*;
33         match terminator.kind {
34             Return => {
35                 self.dump_local(self.frame().return_lvalue);
36                 self.pop_stack_frame()?
37             }
38
39             Goto { target } => self.goto_block(target),
40
41             SwitchInt { ref discr, ref values, ref targets, .. } => {
42                 if self.const_env() {
43                     return Err(EvalError::NeedsRfc("branching (if, match, loop, ...)".to_string()));
44                 }
45                 let discr_val = self.eval_operand(discr)?;
46                 let discr_ty = self.operand_ty(discr);
47                 let discr_prim = self.value_to_primval(discr_val, discr_ty)?;
48
49                 // Branch to the `otherwise` case by default, if no match is found.
50                 let mut target_block = targets[targets.len() - 1];
51
52                 for (index, const_int) in values.iter().enumerate() {
53                     let prim = PrimVal::Bytes(const_int.to_u128_unchecked());
54                     if discr_prim.to_bytes()? == prim.to_bytes()? {
55                         target_block = targets[index];
56                         break;
57                     }
58                 }
59
60                 self.goto_block(target_block);
61             }
62
63             Call { ref func, ref args, ref destination, .. } => {
64                 let destination = match *destination {
65                     Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)),
66                     None => None,
67                 };
68
69                 let func_ty = self.operand_ty(func);
70                 let (fn_def, sig) = match func_ty.sty {
71                     ty::TyFnPtr(sig) => {
72                         let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?;
73                         let instance = self.memory.get_fn(fn_ptr)?;
74                         let instance_ty = instance.def.def_ty(self.tcx);
75                         let instance_ty = self.monomorphize(instance_ty, instance.substs);
76                         match instance_ty.sty {
77                             ty::TyFnDef(..) => {
78                                 let real_sig = instance_ty.fn_sig(self.tcx);
79                                 let sig = self.erase_lifetimes(&sig);
80                                 let real_sig = self.erase_lifetimes(&real_sig);
81                                 let real_sig = self.tcx.normalize_associated_type(&real_sig);
82                                 if !self.check_sig_compat(sig, real_sig)? {
83                                     return Err(EvalError::FunctionPointerTyMismatch(real_sig, sig));
84                                 }
85                             },
86                             ref other => bug!("instance def ty: {:?}", other),
87                         }
88                         (instance, sig)
89                     },
90                     ty::TyFnDef(def_id, substs) => (eval_context::resolve(self.tcx, def_id, substs), func_ty.fn_sig(self.tcx)),
91                     _ => {
92                         let msg = format!("can't handle callee of type {:?}", func_ty);
93                         return Err(EvalError::Unimplemented(msg));
94                     }
95                 };
96                 let sig = self.erase_lifetimes(&sig);
97                 self.eval_fn_call(fn_def, destination, args, terminator.source_info.span, sig)?;
98             }
99
100             Drop { ref location, target, .. } => {
101                 trace!("TerminatorKind::drop: {:?}, {:?}", location, self.substs());
102                 if self.const_env() {
103                     return Err(EvalError::NeedsRfc("invoking `Drop::drop`".to_string()));
104                 }
105                 let lval = self.eval_lvalue(location)?;
106                 let ty = self.lvalue_ty(location);
107                 self.goto_block(target);
108                 let ty = eval_context::apply_param_substs(self.tcx, self.substs(), &ty);
109
110                 let instance = eval_context::resolve_drop_in_place(self.tcx, ty);
111                 self.drop_lvalue(lval, instance, ty, terminator.source_info.span)?;
112             }
113
114             Assert { ref cond, expected, ref msg, target, .. } => {
115                 let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?;
116                 if expected == cond_val {
117                     self.goto_block(target);
118                 } else {
119                     return match *msg {
120                         mir::AssertMessage::BoundsCheck { ref len, ref index } => {
121                             let span = terminator.source_info.span;
122                             let len = self.eval_operand_to_primval(len)
123                                 .expect("can't eval len")
124                                 .to_u64()?;
125                             let index = self.eval_operand_to_primval(index)
126                                 .expect("can't eval index")
127                                 .to_u64()?;
128                             Err(EvalError::ArrayIndexOutOfBounds(span, len, index))
129                         },
130                         mir::AssertMessage::Math(ref err) =>
131                             Err(EvalError::Math(terminator.source_info.span, err.clone())),
132                     }
133                 }
134             },
135
136             DropAndReplace { .. } => unimplemented!(),
137             Resume => unimplemented!(),
138             Unreachable => return Err(EvalError::Unreachable),
139         }
140
141         Ok(())
142     }
143
144     /// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`.
145     /// FIXME: This should take into account the platform-dependent ABI description.
146     fn check_sig_compat(
147         &mut self,
148         sig: ty::FnSig<'tcx>,
149         real_sig: ty::FnSig<'tcx>,
150     ) -> EvalResult<'tcx, bool> {
151         fn check_ty_compat<'tcx>(
152             ty: ty::Ty<'tcx>,
153             real_ty: ty::Ty<'tcx>,
154         ) -> bool {
155             if ty == real_ty { return true; } // This is actually a fast pointer comparison
156             return match (&ty.sty, &real_ty.sty) {
157                 // Permit changing the pointer type of raw pointers and references as well as
158                 // mutability of raw pointers.
159                 // TODO: Should not be allowed when fat pointers are involved.
160                 (&TypeVariants::TyRawPtr(_), &TypeVariants::TyRawPtr(_)) => true,
161                 (&TypeVariants::TyRef(_, _), &TypeVariants::TyRef(_, _)) =>
162                     ty.is_mutable_pointer() == real_ty.is_mutable_pointer(),
163                 // rule out everything else
164                 _ => false
165             }
166         }
167
168         if sig.abi == real_sig.abi &&
169             sig.variadic == real_sig.variadic &&
170             sig.inputs_and_output.len() == real_sig.inputs_and_output.len() &&
171             sig.inputs_and_output.iter().zip(real_sig.inputs_and_output).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
172             // Definitely good.
173             return Ok(true);
174         }
175
176         if sig.variadic || real_sig.variadic {
177             // We're not touching this
178             return Ok(false);
179         }
180
181         // We need to allow what comes up when a non-capturing closure is cast to a fn().
182         match (sig.abi, real_sig.abi) {
183             (Abi::Rust, Abi::RustCall) // check the ABIs.  This makes the test here non-symmetric.
184                 if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => {
185                 // First argument of real_sig must be a ZST
186                 let fst_ty = real_sig.inputs_and_output[0];
187                 let layout = self.type_layout(fst_ty)?;
188                 let size = layout.size(&self.tcx.data_layout).bytes();
189                 if size == 0 {
190                     // Second argument must be a tuple matching the argument list of sig
191                     let snd_ty = real_sig.inputs_and_output[1];
192                     match snd_ty.sty {
193                         TypeVariants::TyTuple(tys, _) if sig.inputs().len() == tys.len() =>
194                             if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
195                                 return Ok(true)
196                             },
197                         _ => {}
198                     }
199                 }
200             }
201             _ => {}
202         };
203
204         // Nope, this doesn't work.
205         return Ok(false);
206     }
207
208     fn eval_fn_call(
209         &mut self,
210         instance: ty::Instance<'tcx>,
211         destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
212         arg_operands: &[mir::Operand<'tcx>],
213         span: Span,
214         sig: ty::FnSig<'tcx>,
215     ) -> EvalResult<'tcx> {
216         trace!("eval_fn_call: {:#?}", instance);
217         match instance.def {
218             ty::InstanceDef::Intrinsic(..) => {
219                 let (ret, target) = match destination {
220                     Some(dest) => dest,
221                     _ => return Err(EvalError::Unreachable),
222                 };
223                 let ty = sig.output();
224                 if !is_inhabited(self.tcx, ty) {
225                     return Err(EvalError::Unreachable);
226                 }
227                 let layout = self.type_layout(ty)?;
228                 self.call_intrinsic(instance, arg_operands, ret, ty, layout, target)?;
229                 self.dump_local(ret);
230                 Ok(())
231             },
232             ty::InstanceDef::ClosureOnceShim{..} => {
233                 let mut args = Vec::new();
234                 for arg in arg_operands {
235                     let arg_val = self.eval_operand(arg)?;
236                     let arg_ty = self.operand_ty(arg);
237                     args.push((arg_val, arg_ty));
238                 }
239                 if self.eval_fn_call_inner(
240                     instance,
241                     destination,
242                     arg_operands,
243                     span,
244                     sig,
245                 )? {
246                     return Ok(());
247                 }
248                 let mut arg_locals = self.frame().mir.args_iter();
249                 match sig.abi {
250                     // closure as closure once
251                     Abi::RustCall => {
252                         for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
253                             let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
254                             self.write_value(arg_val, dest, arg_ty)?;
255                         }
256                     },
257                     // non capture closure as fn ptr
258                     // need to inject zst ptr for closure object (aka do nothing)
259                     // and need to pack arguments
260                     Abi::Rust => {
261                         trace!("arg_locals: {:?}", self.frame().mir.args_iter().collect::<Vec<_>>());
262                         trace!("arg_operands: {:?}", arg_operands);
263                         let local = arg_locals.nth(1).unwrap();
264                         for (i, (arg_val, arg_ty)) in args.into_iter().enumerate() {
265                             let dest = self.eval_lvalue(&mir::Lvalue::Local(local).field(mir::Field::new(i), arg_ty))?;
266                             self.write_value(arg_val, dest, arg_ty)?;
267                         }
268                     },
269                     _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
270                 }
271                 Ok(())
272             }
273             ty::InstanceDef::Item(_) => {
274                 let mut args = Vec::new();
275                 for arg in arg_operands {
276                     let arg_val = self.eval_operand(arg)?;
277                     let arg_ty = self.operand_ty(arg);
278                     args.push((arg_val, arg_ty));
279                 }
280
281                 // Push the stack frame, and potentially be entirely done if the call got hooked
282                 if self.eval_fn_call_inner(
283                     instance,
284                     destination,
285                     arg_operands,
286                     span,
287                     sig,
288                 )? {
289                     return Ok(());
290                 }
291
292                 // Pass the arguments
293                 let mut arg_locals = self.frame().mir.args_iter();
294                 trace!("ABI: {:?}", sig.abi);
295                 trace!("arg_locals: {:?}", self.frame().mir.args_iter().collect::<Vec<_>>());
296                 trace!("arg_operands: {:?}", arg_operands);
297                 match sig.abi {
298                     Abi::RustCall => {
299                         assert_eq!(args.len(), 2);
300
301                         {   // write first argument
302                             let first_local = arg_locals.next().unwrap();
303                             let dest = self.eval_lvalue(&mir::Lvalue::Local(first_local))?;
304                             let (arg_val, arg_ty) = args.remove(0);
305                             self.write_value(arg_val, dest, arg_ty)?;
306                         }
307
308                         // unpack and write all other args
309                         let (arg_val, arg_ty) = args.remove(0);
310                         let layout = self.type_layout(arg_ty)?;
311                         if let (&ty::TyTuple(fields, _), &Layout::Univariant { ref variant, .. }) = (&arg_ty.sty, layout) {
312                             trace!("fields: {:?}", fields);
313                             if self.frame().mir.args_iter().count() == fields.len() + 1 {
314                                 let offsets = variant.offsets.iter().map(|s| s.bytes());
315                                 match arg_val {
316                                     Value::ByRef(ptr, aligned) => {
317                                         assert!(aligned, "Unaligned ByRef-values cannot occur as function arguments");
318                                         for ((offset, ty), arg_local) in offsets.zip(fields).zip(arg_locals) {
319                                             let arg = Value::ByRef(ptr.offset(offset, &self)?, true);
320                                             let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
321                                             trace!("writing arg {:?} to {:?} (type: {})", arg, dest, ty);
322                                             self.write_value(arg, dest, ty)?;
323                                         }
324                                     },
325                                     Value::ByVal(PrimVal::Undef) => {},
326                                     other => {
327                                         assert_eq!(fields.len(), 1);
328                                         let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_locals.next().unwrap()))?;
329                                         self.write_value(other, dest, fields[0])?;
330                                     }
331                                 }
332                             } else {
333                                 trace!("manual impl of rust-call ABI");
334                                 // called a manual impl of a rust-call function
335                                 let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_locals.next().unwrap()))?;
336                                 self.write_value(arg_val, dest, arg_ty)?;
337                             }
338                         } else {
339                             bug!("rust-call ABI tuple argument was {:?}, {:?}", arg_ty, layout);
340                         }
341                     },
342                     _ => {
343                         for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
344                             let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
345                             self.write_value(arg_val, dest, arg_ty)?;
346                         }
347                     }
348                 }
349                 Ok(())
350             },
351             ty::InstanceDef::DropGlue(..) => {
352                 assert_eq!(arg_operands.len(), 1);
353                 assert_eq!(sig.abi, Abi::Rust);
354                 let val = self.eval_operand(&arg_operands[0])?;
355                 let ty = self.operand_ty(&arg_operands[0]);
356                 let (_, target) = destination.expect("diverging drop glue");
357                 self.goto_block(target);
358                 // FIXME: deduplicate these matches
359                 let pointee_type = match ty.sty {
360                     ty::TyRawPtr(ref tam) |
361                     ty::TyRef(_, ref tam) => tam.ty,
362                     ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
363                     _ => bug!("can only deref pointer types"),
364                 };
365                 self.drop(val, instance, pointee_type, span)
366             },
367             ty::InstanceDef::FnPtrShim(..) => {
368                 trace!("ABI: {}", sig.abi);
369                 let mut args = Vec::new();
370                 for arg in arg_operands {
371                     let arg_val = self.eval_operand(arg)?;
372                     let arg_ty = self.operand_ty(arg);
373                     args.push((arg_val, arg_ty));
374                 }
375                 if self.eval_fn_call_inner(
376                     instance,
377                     destination,
378                     arg_operands,
379                     span,
380                     sig,
381                 )? {
382                     return Ok(());
383                 }
384                 let arg_locals = self.frame().mir.args_iter();
385                 match sig.abi {
386                     Abi::Rust => {
387                         args.remove(0);
388                     },
389                     Abi::RustCall => {},
390                     _ => unimplemented!(),
391                 };
392                 for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
393                     let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
394                     self.write_value(arg_val, dest, arg_ty)?;
395                 }
396                 Ok(())
397             },
398             ty::InstanceDef::Virtual(_, idx) => {
399                 let ptr_size = self.memory.pointer_size();
400                 let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(&mut self.memory)?;
401                 let fn_ptr = self.memory.read_ptr(vtable.offset(ptr_size * (idx as u64 + 3), &self)?)?;
402                 let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?;
403                 let mut arg_operands = arg_operands.to_vec();
404                 let ty = self.operand_ty(&arg_operands[0]);
405                 let ty = self.get_field_ty(ty, 0)?;
406                 match arg_operands[0] {
407                     mir::Operand::Consume(ref mut lval) => *lval = lval.clone().field(mir::Field::new(0), ty),
408                     _ => bug!("virtual call first arg cannot be a constant"),
409                 }
410                 // recurse with concrete function
411                 self.eval_fn_call(
412                     instance,
413                     destination,
414                     &arg_operands,
415                     span,
416                     sig,
417                 )
418             },
419         }
420     }
421
422     /// Returns Ok(true) when the function was handled completely due to mir not being available
423     fn eval_fn_call_inner(
424         &mut self,
425         instance: ty::Instance<'tcx>,
426         destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
427         arg_operands: &[mir::Operand<'tcx>],
428         span: Span,
429         sig: ty::FnSig<'tcx>,
430     ) -> EvalResult<'tcx, bool> {
431         trace!("eval_fn_call_inner: {:#?}, {:#?}", instance, destination);
432
433         // Only trait methods can have a Self parameter.
434
435         let mir = match self.load_mir(instance.def) {
436             Ok(mir) => mir,
437             Err(EvalError::NoMirFor(path)) => {
438                 if self.const_env() {
439                     return Err(EvalError::NeedsRfc(format!("calling extern function `{}`", path)));
440                 }
441                 self.call_missing_fn(instance, destination, arg_operands, sig, path)?;
442                 return Ok(true);
443             },
444             Err(other) => return Err(other),
445         };
446
447         if self.const_env() && !self.tcx.is_const_fn(instance.def_id()) {
448             return Err(EvalError::NotConst(format!("calling non-const fn `{}`", instance)));
449         }
450         
451         let (return_lvalue, return_to_block) = match destination {
452             Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
453             None => (Lvalue::undef(), StackPopCleanup::None),
454         };
455
456         self.push_stack_frame(
457             instance,
458             span,
459             mir,
460             return_lvalue,
461             return_to_block,
462         )?;
463
464         Ok(false)
465     }
466
467     pub fn read_discriminant_value(&self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
468         use rustc::ty::layout::Layout::*;
469         let adt_layout = self.type_layout(adt_ty)?;
470         //trace!("read_discriminant_value {:#?}", adt_layout);
471
472         let discr_val = match *adt_layout {
473             General { discr, .. } | CEnum { discr, signed: false, .. } => {
474                 let discr_size = discr.size().bytes();
475                 self.memory.read_uint(adt_ptr, discr_size)?
476             }
477
478             CEnum { discr, signed: true, .. } => {
479                 let discr_size = discr.size().bytes();
480                 self.memory.read_int(adt_ptr, discr_size)? as u128
481             }
482
483             RawNullablePointer { nndiscr, value } => {
484                 let discr_size = value.size(&self.tcx.data_layout).bytes();
485                 trace!("rawnullablepointer with size {}", discr_size);
486                 self.read_nonnull_discriminant_value(adt_ptr, nndiscr as u128, discr_size)?
487             }
488
489             StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
490                 let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
491                 let nonnull = adt_ptr.offset(offset.bytes(), self)?;
492                 trace!("struct wrapped nullable pointer type: {}", ty);
493                 // only the pointer part of a fat pointer is used for this space optimization
494                 let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
495                 self.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size)?
496             }
497
498             // The discriminant_value intrinsic returns 0 for non-sum types.
499             Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
500             Vector { .. } | UntaggedUnion { .. } => 0,
501         };
502
503         Ok(discr_val)
504     }
505
506     fn read_nonnull_discriminant_value(&self, ptr: MemoryPointer, nndiscr: u128, discr_size: u64) -> EvalResult<'tcx, u128> {
507         trace!("read_nonnull_discriminant_value: {:?}, {}, {}", ptr, nndiscr, discr_size);
508         let not_null = match self.memory.read_uint(ptr, discr_size) {
509             Ok(0) => false,
510             Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
511             Err(e) => return Err(e),
512         };
513         assert!(nndiscr == 0 || nndiscr == 1);
514         Ok(if not_null { nndiscr } else { 1 - nndiscr })
515     }
516     
517     /// Returns Ok() when the function was handled, fail otherwise
518     fn call_missing_fn(
519         &mut self,
520         instance: ty::Instance<'tcx>,
521         destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
522         arg_operands: &[mir::Operand<'tcx>],
523         sig: ty::FnSig<'tcx>,
524         path: String,
525     ) -> EvalResult<'tcx> {
526         // In some cases in non-MIR libstd-mode, not having a destination is legit.  Handle these early.
527         match &path[..] {
528             "std::panicking::rust_panic_with_hook" |
529             "std::rt::begin_panic_fmt" => return Err(EvalError::Panic),
530             _ => {},
531         }
532
533         let dest_ty = sig.output();
534         let (dest, dest_block) = destination.ok_or_else(|| EvalError::NoMirFor(path.clone()))?;
535
536         if sig.abi == Abi::C {
537             // An external C function
538             // TODO: That functions actually has a similar preamble to what follows here.  May make sense to
539             // unify these two mechanisms for "hooking into missing functions".
540             self.call_c_abi(instance.def_id(), arg_operands, dest, dest_ty, dest_block)?;
541             return Ok(());
542         }
543
544         let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
545             .map(|arg| self.eval_operand(arg))
546             .collect();
547         let args = args_res?;
548
549         let usize = self.tcx.types.usize;
550     
551         match &path[..] {
552             // Allocators are magic.  They have no MIR, even when the rest of libstd does.
553             "alloc::heap::::__rust_alloc" => {
554                 let size = self.value_to_primval(args[0], usize)?.to_u64()?;
555                 let align = self.value_to_primval(args[1], usize)?.to_u64()?;
556                 if size == 0 {
557                     return Err(EvalError::HeapAllocZeroBytes);
558                 }
559                 if !align.is_power_of_two() {
560                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
561                 }
562                 let ptr = self.memory.allocate(size, align, Kind::Rust)?;
563                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
564             }
565             "alloc::heap::::__rust_alloc_zeroed" => {
566                 let size = self.value_to_primval(args[0], usize)?.to_u64()?;
567                 let align = self.value_to_primval(args[1], usize)?.to_u64()?;
568                 if size == 0 {
569                     return Err(EvalError::HeapAllocZeroBytes);
570                 }
571                 if !align.is_power_of_two() {
572                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
573                 }
574                 let ptr = self.memory.allocate(size, align, Kind::Rust)?;
575                 self.memory.write_repeat(ptr.into(), 0, size)?;
576                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
577             }
578             "alloc::heap::::__rust_dealloc" => {
579                 let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
580                 let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
581                 let align = self.value_to_primval(args[2], usize)?.to_u64()?;
582                 if old_size == 0 {
583                     return Err(EvalError::HeapAllocZeroBytes);
584                 }
585                 if !align.is_power_of_two() {
586                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
587                 }
588                 self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust)?;
589             }
590             "alloc::heap::::__rust_realloc" => {
591                 let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
592                 let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
593                 let old_align = self.value_to_primval(args[2], usize)?.to_u64()?;
594                 let new_size = self.value_to_primval(args[3], usize)?.to_u64()?;
595                 let new_align = self.value_to_primval(args[4], usize)?.to_u64()?;
596                 if old_size == 0 || new_size == 0 {
597                     return Err(EvalError::HeapAllocZeroBytes);
598                 }
599                 if !old_align.is_power_of_two() {
600                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(old_align));
601                 }
602                 if !new_align.is_power_of_two() {
603                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(new_align));
604                 }
605                 let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align, Kind::Rust)?;
606                 self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
607             }
608
609             // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
610             // Still, we can make many things mostly work by "emulating" or ignoring some functions.
611             "std::io::_print" => {
612                 trace!("Ignoring output.  To run programs that print, make sure you have a libstd with full MIR.");
613             }
614             "std::thread::Builder::new" => return Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
615             "std::env::args" => return Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
616             "std::panicking::panicking" |
617             "std::rt::panicking" => {
618                 // we abort on panic -> `std::rt::panicking` always returns false
619                 let bool = self.tcx.types.bool;
620                 self.write_primval(dest, PrimVal::from_bool(false), bool)?;
621             }
622             _ => return Err(EvalError::NoMirFor(path)),
623         }
624
625         // Since we pushed no stack frame, the main loop will act
626         // as if the call just completed and it's returning to the
627         // current frame.
628         self.dump_local(dest);
629         self.goto_block(dest_block);
630         return Ok(());
631     }
632
633     fn call_c_abi(
634         &mut self,
635         def_id: DefId,
636         arg_operands: &[mir::Operand<'tcx>],
637         dest: Lvalue<'tcx>,
638         dest_ty: Ty<'tcx>,
639         dest_block: mir::BasicBlock,
640     ) -> EvalResult<'tcx> {
641         let name = self.tcx.item_name(def_id);
642         let attrs = self.tcx.get_attrs(def_id);
643         let link_name = attr::first_attr_value_str_by_name(&attrs, "link_name")
644             .unwrap_or(name)
645             .as_str();
646
647         let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
648             .map(|arg| self.eval_operand(arg))
649             .collect();
650         let args = args_res?;
651
652         let usize = self.tcx.types.usize;
653
654         match &link_name[..] {
655             "malloc" => {
656                 let size = self.value_to_primval(args[0], usize)?.to_u64()?;
657                 if size == 0 {
658                     self.write_null(dest, dest_ty)?;
659                 } else {
660                     let align = self.memory.pointer_size();
661                     let ptr = self.memory.allocate(size, align, Kind::C)?;
662                     self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
663                 }
664             }
665
666             "free" => {
667                 let ptr = args[0].into_ptr(&mut self.memory)?;
668                 if !ptr.is_null()? {
669                     self.memory.deallocate(ptr.to_ptr()?, None, Kind::C)?;
670                 }
671             }
672
673             "syscall" => {
674                 match self.value_to_primval(args[0], usize)?.to_u64()? {
675                     511 => return Err(EvalError::Unimplemented("miri does not support random number generators".to_owned())),
676                     id => return Err(EvalError::Unimplemented(format!("miri does not support syscall id {}", id))),
677                 }
678             }
679
680             "dlsym" => {
681                 let _handle = args[0].into_ptr(&mut self.memory)?;
682                 let symbol = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
683                 let symbol_name = self.memory.read_c_str(symbol)?;
684                 let err = format!("bad c unicode symbol: {:?}", symbol_name);
685                 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
686                 return Err(EvalError::Unimplemented(format!("miri does not support dynamically loading libraries (requested symbol: {})", symbol_name)));
687             }
688
689             "__rust_maybe_catch_panic" => {
690                 // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
691                 // We abort on panic, so not much is going on here, but we still have to call the closure
692                 let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
693                 let f = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
694                 let data = args[1].into_ptr(&mut self.memory)?;
695                 let f_instance = self.memory.get_fn(f)?;
696                 self.write_null(dest, dest_ty)?;
697
698                 // Now we make a function call.  TODO: Consider making this re-usable?  EvalContext::step does sth. similar for the TLS dtors,
699                 // and of course eval_main.
700                 let mir = self.load_mir(f_instance.def)?;
701                 self.push_stack_frame(
702                     f_instance,
703                     mir.span,
704                     mir,
705                     Lvalue::undef(),
706                     StackPopCleanup::Goto(dest_block),
707                 )?;
708
709                 let arg_local = self.frame().mir.args_iter().next().ok_or(EvalError::AbiViolation("Argument to __rust_maybe_catch_panic does not take enough arguments.".to_owned()))?;
710                 let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
711                 self.write_ptr(arg_dest, data, u8_ptr_ty)?;
712
713                 // We ourselves return 0
714                 self.write_null(dest, dest_ty)?;
715
716                 // Don't fall through
717                 return Ok(());
718             }
719
720             "__rust_start_panic" => {
721                 return Err(EvalError::Panic);
722             }
723
724             "memcmp" => {
725                 let left = args[0].into_ptr(&mut self.memory)?;
726                 let right = args[1].into_ptr(&mut self.memory)?;
727                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
728
729                 let result = {
730                     let left_bytes = self.memory.read_bytes(left, n)?;
731                     let right_bytes = self.memory.read_bytes(right, n)?;
732
733                     use std::cmp::Ordering::*;
734                     match left_bytes.cmp(right_bytes) {
735                         Less => -1i8,
736                         Equal => 0,
737                         Greater => 1,
738                     }
739                 };
740
741                 self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
742             }
743
744             "memrchr" => {
745                 let ptr = args[0].into_ptr(&mut self.memory)?;
746                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
747                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
748                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) {
749                     let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?;
750                     self.write_ptr(dest, new_ptr, dest_ty)?;
751                 } else {
752                     self.write_null(dest, dest_ty)?;
753                 }
754             }
755
756             "memchr" => {
757                 let ptr = args[0].into_ptr(&mut self.memory)?;
758                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
759                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
760                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
761                     let new_ptr = ptr.offset(idx as u64, &self)?;
762                     self.write_ptr(dest, new_ptr, dest_ty)?;
763                 } else {
764                     self.write_null(dest, dest_ty)?;
765                 }
766             }
767
768             "getenv" => {
769                 let result = {
770                     let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
771                     let name = self.memory.read_c_str(name_ptr)?;
772                     match self.env_vars.get(name) {
773                         Some(&var) => PrimVal::Ptr(var),
774                         None => PrimVal::Bytes(0),
775                     }
776                 };
777                 self.write_primval(dest, result, dest_ty)?;
778             }
779
780             "unsetenv" => {
781                 let mut success = None;
782                 {
783                     let name_ptr = args[0].into_ptr(&mut self.memory)?;
784                     if !name_ptr.is_null()? {
785                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
786                         if !name.is_empty() && !name.contains(&b'=') {
787                             success = Some(self.env_vars.remove(name));
788                         }
789                     }
790                 }
791                 if let Some(old) = success {
792                     if let Some(var) = old {
793                         self.memory.deallocate(var, None, Kind::Env)?;
794                     }
795                     self.write_null(dest, dest_ty)?;
796                 } else {
797                     self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
798                 }
799             }
800
801             "setenv" => {
802                 let mut new = None;
803                 {
804                     let name_ptr = args[0].into_ptr(&mut self.memory)?;
805                     let value_ptr = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
806                     let value = self.memory.read_c_str(value_ptr)?;
807                     if !name_ptr.is_null()? {
808                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
809                         if !name.is_empty() && !name.contains(&b'=') {
810                             new = Some((name.to_owned(), value.to_owned()));
811                         }
812                     }
813                 }
814                 if let Some((name, value)) = new {
815                     // +1 for the null terminator
816                     let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, Kind::Env)?;
817                     self.memory.write_bytes(value_copy.into(), &value)?;
818                     let trailing_null = value_copy.offset(value.len() as u64, &self)?.into();
819                     self.memory.write_bytes(trailing_null, &[0])?;
820                     if let Some(var) = self.env_vars.insert(name.to_owned(), value_copy) {
821                         self.memory.deallocate(var, None, Kind::Env)?;
822                     }
823                     self.write_null(dest, dest_ty)?;
824                 } else {
825                     self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
826                 }
827             }
828
829             "write" => {
830                 let fd = self.value_to_primval(args[0], usize)?.to_u64()?;
831                 let buf = args[1].into_ptr(&mut self.memory)?;
832                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
833                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
834                 let result = if fd == 1 || fd == 2 { // stdout/stderr
835                     use std::io::{self, Write};
836                 
837                     let buf_cont = self.memory.read_bytes(buf, n)?;
838                     let res = if fd == 1 { io::stdout().write(buf_cont) } else { io::stderr().write(buf_cont) };
839                     match res { Ok(n) => n as isize, Err(_) => -1 }
840                 } else {
841                     info!("Ignored output to FD {}", fd);
842                     n as isize // pretend it all went well
843                 }; // now result is the value we return back to the program
844                 self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
845             }
846
847             "strlen" => {
848                 let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
849                 let n = self.memory.read_c_str(ptr)?.len();
850                 self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
851             }
852
853             // Some things needed for sys::thread initialization to go through
854             "signal" | "sigaction" | "sigaltstack" => {
855                 self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
856             }
857
858             "sysconf" => {
859                 let name = self.value_to_primval(args[0], usize)?.to_u64()?;
860                 trace!("sysconf() called with name {}", name);
861                 // cache the sysconf integers via miri's global cache
862                 let paths = &[
863                     (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)),
864                     (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)),
865                 ];
866                 let mut result = None;
867                 for &(path, path_value) in paths {
868                     if let Ok(instance) = self.resolve_path(path) {
869                         use lvalue::GlobalId;
870                         let cid = GlobalId { instance, promoted: None };
871                         // compute global if not cached
872                         let val = match self.globals.get(&cid).map(|glob| glob.value) {
873                             Some(value) => self.value_to_primval(value, usize)?.to_u64()?,
874                             None => const_eval::eval_body_as_primval(self.tcx, instance)?.0.to_u64()?,
875                         };
876                         if val == name {
877                             result = Some(path_value);
878                             break;
879                         }
880                     }
881                 }
882                 if let Some(result) = result {
883                     self.write_primval(dest, result, dest_ty)?;
884                 } else {
885                     return Err(EvalError::Unimplemented(format!("Unimplemented sysconf name: {}", name)));
886                 }
887             }
888
889             // Hook pthread calls that go to the thread-local storage memory subsystem
890             "pthread_key_create" => {
891                 let key_ptr = args[0].into_ptr(&mut self.memory)?;
892
893                 // Extract the function type out of the signature (that seems easier than constructing it ourselves...)
894                 let dtor = match args[1].into_ptr(&mut self.memory)?.into_inner_primval() {
895                     PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?),
896                     PrimVal::Bytes(0) => None,
897                     PrimVal::Bytes(_) => return Err(EvalError::ReadBytesAsPointer),
898                     PrimVal::Undef => return Err(EvalError::ReadUndefBytes),
899                 };
900
901                 // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
902                 let key_type = self.operand_ty(&arg_operands[0]).builtin_deref(true, ty::LvaluePreference::NoPreference)
903                                    .ok_or(EvalError::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
904                 let key_size = {
905                     let layout = self.type_layout(key_type)?;
906                     layout.size(&self.tcx.data_layout)
907                 };
908
909                 // Create key and write it into the memory where key_ptr wants it
910                 let key = self.memory.create_tls_key(dtor) as u128;
911                 if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) {
912                     return Err(EvalError::OutOfTls);
913                 }
914                 // TODO: Does this need checking for alignment?
915                 self.memory.write_uint(key_ptr.to_ptr()?, key, key_size.bytes())?;
916
917                 // Return success (0)
918                 self.write_null(dest, dest_ty)?;
919             }
920             "pthread_key_delete" => {
921                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
922                 let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey;
923                 self.memory.delete_tls_key(key)?;
924                 // Return success (0)
925                 self.write_null(dest, dest_ty)?;
926             }
927             "pthread_getspecific" => {
928                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
929                 let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey;
930                 let ptr = self.memory.load_tls(key)?;
931                 self.write_ptr(dest, ptr, dest_ty)?;
932             }
933             "pthread_setspecific" => {
934                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
935                 let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey;
936                 let new_ptr = args[1].into_ptr(&mut self.memory)?;
937                 self.memory.store_tls(key, new_ptr)?;
938                 
939                 // Return success (0)
940                 self.write_null(dest, dest_ty)?;
941             }
942
943             // Stub out all the other pthread calls to just return 0
944             link_name if link_name.starts_with("pthread_") => {
945                 warn!("ignoring C ABI call: {}", link_name);
946                 self.write_null(dest, dest_ty)?;
947             },
948
949             _ => {
950                 return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name)));
951             }
952         }
953
954         // Since we pushed no stack frame, the main loop will act
955         // as if the call just completed and it's returning to the
956         // current frame.
957         self.dump_local(dest);
958         self.goto_block(dest_block);
959         Ok(())
960     }
961
962     /// Get an instance for a path.
963     fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> {
964         let cstore = &self.tcx.sess.cstore;
965
966         let crates = cstore.crates();
967         crates.iter()
968             .find(|&&krate| cstore.crate_name(krate) == path[0])
969             .and_then(|krate| {
970                 let krate = DefId {
971                     krate: *krate,
972                     index: CRATE_DEF_INDEX,
973                 };
974                 let mut items = cstore.item_children(krate, self.tcx.sess);
975                 let mut path_it = path.iter().skip(1).peekable();
976
977                 while let Some(segment) = path_it.next() {
978                     for item in &mem::replace(&mut items, vec![]) {
979                         if item.ident.name == *segment {
980                             if path_it.peek().is_none() {
981                                 return Some(ty::Instance::mono(self.tcx, item.def.def_id()));
982                             }
983
984                             items = cstore.item_children(item.def.def_id(), self.tcx.sess);
985                             break;
986                         }
987                     }
988                 }
989                 None
990             })
991             .ok_or_else(|| {
992                 let path = path.iter()
993                     .map(|&s| s.to_owned())
994                     .collect();
995                 EvalError::PathNotFound(path)
996             })
997     }
998 }