1 use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
3 use rustc::ty::{self, TypeVariants, Ty};
4 use rustc::ty::layout::Layout;
5 use syntax::codemap::Span;
9 use error::{EvalError, EvalResult};
10 use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited, self};
12 use memory::{MemoryPointer, TlsKey, Kind};
13 use value::{PrimVal, Value};
14 use rustc_data_structures::indexed_vec::Idx;
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;
28 pub(super) fn eval_terminator(
30 terminator: &mir::Terminator<'tcx>,
31 ) -> EvalResult<'tcx> {
32 use rustc::mir::TerminatorKind::*;
33 match terminator.kind {
35 self.dump_local(self.frame().return_lvalue);
36 self.pop_stack_frame()?
39 Goto { target } => self.goto_block(target),
41 SwitchInt { ref discr, ref values, ref targets, .. } => {
43 return Err(EvalError::NeedsRfc("branching (if, match, loop, ...)".to_string()));
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)?;
49 // Branch to the `otherwise` case by default, if no match is found.
50 let mut target_block = targets[targets.len() - 1];
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];
60 self.goto_block(target_block);
63 Call { ref func, ref args, ref destination, .. } => {
64 let destination = match *destination {
65 Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)),
69 let func_ty = self.operand_ty(func);
70 let (fn_def, sig) = match func_ty.sty {
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 {
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));
86 ref other => bug!("instance def ty: {:?}", other),
90 ty::TyFnDef(def_id, substs) => (eval_context::resolve(self.tcx, def_id, substs), func_ty.fn_sig(self.tcx)),
92 let msg = format!("can't handle callee of type {:?}", func_ty);
93 return Err(EvalError::Unimplemented(msg));
96 let sig = self.erase_lifetimes(&sig);
97 self.eval_fn_call(fn_def, destination, args, terminator.source_info.span, sig)?;
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()));
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);
110 let instance = eval_context::resolve_drop_in_place(self.tcx, ty);
111 self.drop_lvalue(lval, instance, ty, terminator.source_info.span)?;
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);
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")
125 let index = self.eval_operand_to_primval(index)
126 .expect("can't eval index")
128 Err(EvalError::ArrayIndexOutOfBounds(span, len, index))
130 mir::AssertMessage::Math(ref err) =>
131 Err(EvalError::Math(terminator.source_info.span, err.clone())),
136 DropAndReplace { .. } => unimplemented!(),
137 Resume => unimplemented!(),
138 Unreachable => return Err(EvalError::Unreachable),
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.
148 sig: ty::FnSig<'tcx>,
149 real_sig: ty::FnSig<'tcx>,
150 ) -> EvalResult<'tcx, bool> {
151 fn check_ty_compat<'tcx>(
153 real_ty: ty::Ty<'tcx>,
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
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)) {
176 if sig.variadic || real_sig.variadic {
177 // We're not touching this
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();
190 // Second argument must be a tuple matching the argument list of sig
191 let snd_ty = real_sig.inputs_and_output[1];
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)) {
204 // Nope, this doesn't work.
210 instance: ty::Instance<'tcx>,
211 destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
212 arg_operands: &[mir::Operand<'tcx>],
214 sig: ty::FnSig<'tcx>,
215 ) -> EvalResult<'tcx> {
216 trace!("eval_fn_call: {:#?}", instance);
218 ty::InstanceDef::Intrinsic(..) => {
219 let (ret, target) = match destination {
221 _ => return Err(EvalError::Unreachable),
223 let ty = sig.output();
224 if !is_inhabited(self.tcx, ty) {
225 return Err(EvalError::Unreachable);
227 let layout = self.type_layout(ty)?;
228 self.call_intrinsic(instance, arg_operands, ret, ty, layout, target)?;
229 self.dump_local(ret);
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));
239 if self.eval_fn_call_inner(
248 let mut arg_locals = self.frame().mir.args_iter();
250 // closure as closure once
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)?;
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
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)?;
269 _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
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));
281 // Push the stack frame, and potentially be entirely done if the call got hooked
282 if self.eval_fn_call_inner(
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);
299 assert_eq!(args.len(), 2);
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)?;
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());
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)?;
325 Value::ByVal(PrimVal::Undef) => {},
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])?;
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)?;
339 bug!("rust-call ABI tuple argument was {:?}, {:?}", arg_ty, layout);
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)?;
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"),
365 self.drop(val, instance, pointee_type, span)
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));
375 if self.eval_fn_call_inner(
384 let arg_locals = self.frame().mir.args_iter();
390 _ => unimplemented!(),
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)?;
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"),
410 // recurse with concrete function
422 /// Returns Ok(true) when the function was handled completely due to mir not being available
423 fn eval_fn_call_inner(
425 instance: ty::Instance<'tcx>,
426 destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
427 arg_operands: &[mir::Operand<'tcx>],
429 sig: ty::FnSig<'tcx>,
430 ) -> EvalResult<'tcx, bool> {
431 trace!("eval_fn_call_inner: {:#?}, {:#?}", instance, destination);
433 // Only trait methods can have a Self parameter.
435 let mir = match self.load_mir(instance.def) {
437 Err(EvalError::NoMirFor(path)) => {
438 if self.const_env() {
439 return Err(EvalError::NeedsRfc(format!("calling extern function `{}`", path)));
441 self.call_missing_fn(instance, destination, arg_operands, sig, path)?;
444 Err(other) => return Err(other),
447 if self.const_env() && !self.tcx.is_const_fn(instance.def_id()) {
448 return Err(EvalError::NotConst(format!("calling non-const fn `{}`", instance)));
451 let (return_lvalue, return_to_block) = match destination {
452 Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
453 None => (Lvalue::undef(), StackPopCleanup::None),
456 self.push_stack_frame(
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);
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)?
478 CEnum { discr, signed: true, .. } => {
479 let discr_size = discr.size().bytes();
480 self.memory.read_int(adt_ptr, discr_size)? as u128
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)?
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)?
498 // The discriminant_value intrinsic returns 0 for non-sum types.
499 Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
500 Vector { .. } | UntaggedUnion { .. } => 0,
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) {
510 Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
511 Err(e) => return Err(e),
513 assert!(nndiscr == 0 || nndiscr == 1);
514 Ok(if not_null { nndiscr } else { 1 - nndiscr })
517 /// Returns Ok() when the function was handled, fail otherwise
520 instance: ty::Instance<'tcx>,
521 destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
522 arg_operands: &[mir::Operand<'tcx>],
523 sig: ty::FnSig<'tcx>,
525 ) -> EvalResult<'tcx> {
526 // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early.
528 "std::panicking::rust_panic_with_hook" |
529 "std::rt::begin_panic_fmt" => return Err(EvalError::Panic),
533 let dest_ty = sig.output();
534 let (dest, dest_block) = destination.ok_or_else(|| EvalError::NoMirFor(path.clone()))?;
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)?;
544 let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
545 .map(|arg| self.eval_operand(arg))
547 let args = args_res?;
549 let usize = self.tcx.types.usize;
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()?;
557 return Err(EvalError::HeapAllocZeroBytes);
559 if !align.is_power_of_two() {
560 return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
562 let ptr = self.memory.allocate(size, align, Kind::Rust)?;
563 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
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()?;
569 return Err(EvalError::HeapAllocZeroBytes);
571 if !align.is_power_of_two() {
572 return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
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)?;
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()?;
583 return Err(EvalError::HeapAllocZeroBytes);
585 if !align.is_power_of_two() {
586 return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
588 self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust)?;
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);
599 if !old_align.is_power_of_two() {
600 return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(old_align));
602 if !new_align.is_power_of_two() {
603 return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(new_align));
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)?;
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.");
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)?;
622 _ => return Err(EvalError::NoMirFor(path)),
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
628 self.dump_local(dest);
629 self.goto_block(dest_block);
636 arg_operands: &[mir::Operand<'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")
647 let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
648 .map(|arg| self.eval_operand(arg))
650 let args = args_res?;
652 let usize = self.tcx.types.usize;
654 match &link_name[..] {
656 let size = self.value_to_primval(args[0], usize)?.to_u64()?;
658 self.write_null(dest, dest_ty)?;
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)?;
667 let ptr = args[0].into_ptr(&mut self.memory)?;
669 self.memory.deallocate(ptr.to_ptr()?, None, Kind::C)?;
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))),
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)));
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)?;
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(
706 StackPopCleanup::Goto(dest_block),
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)?;
713 // We ourselves return 0
714 self.write_null(dest, dest_ty)?;
716 // Don't fall through
720 "__rust_start_panic" => {
721 return Err(EvalError::Panic);
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()?;
730 let left_bytes = self.memory.read_bytes(left, n)?;
731 let right_bytes = self.memory.read_bytes(right, n)?;
733 use std::cmp::Ordering::*;
734 match left_bytes.cmp(right_bytes) {
741 self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
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)?;
752 self.write_null(dest, dest_ty)?;
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)?;
764 self.write_null(dest, dest_ty)?;
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),
777 self.write_primval(dest, result, dest_ty)?;
781 let mut success = None;
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));
791 if let Some(old) = success {
792 if let Some(var) = old {
793 self.memory.deallocate(var, None, Kind::Env)?;
795 self.write_null(dest, dest_ty)?;
797 self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
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()));
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)?;
823 self.write_null(dest, dest_ty)?;
825 self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
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};
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 }
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)?;
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)?;
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)?;
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
863 (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)),
864 (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)),
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()?,
877 result = Some(path_value);
882 if let Some(result) = result {
883 self.write_primval(dest, result, dest_ty)?;
885 return Err(EvalError::Unimplemented(format!("Unimplemented sysconf name: {}", name)));
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)?;
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),
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;
905 let layout = self.type_layout(key_type)?;
906 layout.size(&self.tcx.data_layout)
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);
914 // TODO: Does this need checking for alignment?
915 self.memory.write_uint(key_ptr.to_ptr()?, key, key_size.bytes())?;
917 // Return success (0)
918 self.write_null(dest, dest_ty)?;
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)?;
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)?;
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)?;
939 // Return success (0)
940 self.write_null(dest, dest_ty)?;
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)?;
950 return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name)));
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
957 self.dump_local(dest);
958 self.goto_block(dest_block);
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;
966 let crates = cstore.crates();
968 .find(|&&krate| cstore.crate_name(krate) == path[0])
972 index: CRATE_DEF_INDEX,
974 let mut items = cstore.item_children(krate, self.tcx.sess);
975 let mut path_it = path.iter().skip(1).peekable();
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()));
984 items = cstore.item_children(item.def.def_id(), self.tcx.sess);
992 let path = path.iter()
993 .map(|&s| s.to_owned())
995 EvalError::PathNotFound(path)