2016-06-23 01:03:58 -06:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir;
|
2017-02-28 12:35:00 +01:00
|
|
|
use rustc::ty::{self, Ty};
|
2017-03-22 13:13:52 +01:00
|
|
|
use rustc::ty::layout::Layout;
|
2017-02-10 03:21:33 -08:00
|
|
|
use syntax::codemap::Span;
|
|
|
|
use syntax::attr;
|
2017-03-02 13:11:33 +01:00
|
|
|
use syntax::abi::Abi;
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
use error::{EvalError, EvalResult};
|
2017-02-09 18:12:59 +01:00
|
|
|
use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited};
|
2017-03-22 18:31:41 +01:00
|
|
|
use lvalue::Lvalue;
|
2017-03-21 13:53:55 +01:00
|
|
|
use memory::Pointer;
|
2016-12-10 16:23:07 -08:00
|
|
|
use value::PrimVal;
|
2016-12-07 20:30:37 -08:00
|
|
|
use value::Value;
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2017-03-22 18:31:41 +01:00
|
|
|
mod drop;
|
2016-12-10 16:27:45 -08:00
|
|
|
mod intrinsic;
|
2016-09-20 16:05:30 +02:00
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
2016-07-06 17:55:05 +02:00
|
|
|
pub(super) fn goto_block(&mut self, target: mir::BasicBlock) {
|
|
|
|
self.frame_mut().block = target;
|
|
|
|
self.frame_mut().stmt = 0;
|
|
|
|
}
|
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
pub(super) fn eval_terminator(
|
|
|
|
&mut self,
|
|
|
|
terminator: &mir::Terminator<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir::TerminatorKind::*;
|
2016-06-23 01:03:58 -06:00
|
|
|
match terminator.kind {
|
2016-11-26 19:13:22 -08:00
|
|
|
Return => {
|
|
|
|
self.dump_local(self.frame().return_lvalue);
|
|
|
|
self.pop_stack_frame()?
|
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2016-07-06 17:55:05 +02:00
|
|
|
Goto { target } => self.goto_block(target),
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
SwitchInt { ref discr, ref values, ref targets, .. } => {
|
2017-02-24 10:39:55 +01:00
|
|
|
let discr_val = self.eval_operand(discr)?;
|
|
|
|
let discr_ty = self.operand_ty(discr);
|
2016-09-27 11:10:25 +02:00
|
|
|
let discr_prim = self.value_to_primval(discr_val, discr_ty)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
// Branch to the `otherwise` case by default, if no match is found.
|
|
|
|
let mut target_block = targets[targets.len() - 1];
|
|
|
|
|
2017-02-24 10:39:55 +01:00
|
|
|
for (index, const_int) in values.iter().enumerate() {
|
|
|
|
let prim = PrimVal::Bytes(const_int.to_u128_unchecked());
|
2016-12-17 03:09:57 -08:00
|
|
|
if discr_prim.to_bytes()? == prim.to_bytes()? {
|
2016-06-23 01:03:58 -06:00
|
|
|
target_block = targets[index];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-06 17:55:05 +02:00
|
|
|
self.goto_block(target_block);
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
Call { ref func, ref args, ref destination, .. } => {
|
2016-07-06 17:55:05 +02:00
|
|
|
let destination = match *destination {
|
2016-10-14 03:31:45 -06:00
|
|
|
Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)),
|
2016-07-06 17:55:05 +02:00
|
|
|
None => None,
|
|
|
|
};
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
let func_ty = self.operand_ty(func);
|
2017-03-22 14:19:29 +01:00
|
|
|
let (fn_def, sig) = match func_ty.sty {
|
2017-03-22 13:13:52 +01:00
|
|
|
ty::TyFnPtr(sig) => {
|
2016-12-16 22:01:01 -08:00
|
|
|
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?;
|
2017-03-22 14:19:29 +01:00
|
|
|
(self.memory.get_fn(fn_ptr.alloc_id)?, sig)
|
2016-06-23 01:03:58 -06:00
|
|
|
},
|
2017-03-22 14:19:29 +01:00
|
|
|
ty::TyFnDef(def_id, substs, sig) => (::eval_context::resolve(self.tcx, def_id, substs), sig),
|
2016-11-26 22:58:01 -08:00
|
|
|
_ => {
|
|
|
|
let msg = format!("can't handle callee of type {:?}", func_ty);
|
|
|
|
return Err(EvalError::Unimplemented(msg));
|
|
|
|
}
|
2017-02-28 12:35:00 +01:00
|
|
|
};
|
2017-03-22 14:19:29 +01:00
|
|
|
let sig = self.erase_lifetimes(&sig);
|
|
|
|
self.eval_fn_call(fn_def, destination, args, terminator.source_info.span, sig)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2017-03-22 13:13:52 +01:00
|
|
|
Drop { ref location, target, .. } => {
|
2017-03-22 17:32:20 +01:00
|
|
|
trace!("TerminatorKind::drop: {:?}, {:?}", location, self.substs());
|
2017-03-22 13:13:52 +01:00
|
|
|
let lval = self.eval_lvalue(location)?;
|
|
|
|
let ty = self.lvalue_ty(location);
|
2017-03-22 17:32:20 +01:00
|
|
|
self.goto_block(target);
|
2017-03-22 16:16:23 +01:00
|
|
|
let ty = ::eval_context::apply_param_substs(self.tcx, self.substs(), &ty);
|
2017-03-22 13:13:52 +01:00
|
|
|
|
2017-03-22 18:31:41 +01:00
|
|
|
let instance = ::eval_context::resolve_drop_in_place(self.tcx, ty);
|
|
|
|
self.drop_lvalue(lval, instance, ty, terminator.source_info.span)?;
|
2017-03-22 13:13:52 +01:00
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
Assert { ref cond, expected, ref msg, target, .. } => {
|
2016-12-16 22:01:01 -08:00
|
|
|
let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?;
|
2016-09-19 02:19:31 -06:00
|
|
|
if expected == cond_val {
|
2016-07-06 17:55:05 +02:00
|
|
|
self.goto_block(target);
|
2016-06-23 01:03:58 -06:00
|
|
|
} else {
|
|
|
|
return match *msg {
|
|
|
|
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
|
2016-09-19 19:01:28 -06:00
|
|
|
let span = terminator.source_info.span;
|
2016-11-26 22:58:01 -08:00
|
|
|
let len = self.eval_operand_to_primval(len)
|
|
|
|
.expect("can't eval len")
|
2016-12-16 22:01:01 -08:00
|
|
|
.to_u64()?;
|
2016-09-19 19:01:28 -06:00
|
|
|
let index = self.eval_operand_to_primval(index)
|
|
|
|
.expect("can't eval index")
|
2016-12-16 22:01:01 -08:00
|
|
|
.to_u64()?;
|
2016-09-19 19:01:28 -06:00
|
|
|
Err(EvalError::ArrayIndexOutOfBounds(span, len, index))
|
2016-06-23 01:03:58 -06:00
|
|
|
},
|
2016-09-19 19:01:28 -06:00
|
|
|
mir::AssertMessage::Math(ref err) =>
|
|
|
|
Err(EvalError::Math(terminator.source_info.span, err.clone())),
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
DropAndReplace { .. } => unimplemented!(),
|
|
|
|
Resume => unimplemented!(),
|
2017-01-12 09:41:36 +01:00
|
|
|
Unreachable => return Err(EvalError::Unreachable),
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn eval_fn_call(
|
|
|
|
&mut self,
|
2017-03-21 13:53:55 +01:00
|
|
|
instance: ty::Instance<'tcx>,
|
2016-10-21 10:29:56 +02:00
|
|
|
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
2016-09-19 19:40:56 -06:00
|
|
|
arg_operands: &[mir::Operand<'tcx>],
|
2016-06-23 01:03:58 -06:00
|
|
|
span: Span,
|
2017-03-22 14:19:29 +01:00
|
|
|
sig: ty::FnSig<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2017-03-22 13:13:52 +01:00
|
|
|
trace!("eval_fn_call: {:#?}", instance);
|
|
|
|
match instance.def {
|
|
|
|
ty::InstanceDef::Intrinsic(..) => {
|
2017-01-12 09:59:00 +01:00
|
|
|
let (ret, target) = match destination {
|
2017-03-22 14:19:29 +01:00
|
|
|
Some(dest) => dest,
|
2017-01-12 10:37:14 +01:00
|
|
|
_ => return Err(EvalError::Unreachable),
|
2017-01-12 09:59:00 +01:00
|
|
|
};
|
2017-03-22 14:19:29 +01:00
|
|
|
let ty = sig.output();
|
|
|
|
if !is_inhabited(self.tcx, ty) {
|
|
|
|
return Err(EvalError::Unreachable);
|
|
|
|
}
|
|
|
|
let layout = self.type_layout(ty)?;
|
2017-03-21 13:53:55 +01:00
|
|
|
self.call_intrinsic(instance, arg_operands, ret, ty, layout, target)?;
|
2017-02-07 01:03:40 -08:00
|
|
|
self.dump_local(ret);
|
2017-03-22 14:19:29 +01:00
|
|
|
Ok(())
|
2017-02-28 12:35:00 +01:00
|
|
|
},
|
2017-03-22 13:13:52 +01:00
|
|
|
ty::InstanceDef::ClosureOnceShim{..} => {
|
2016-09-19 19:40:56 -06:00
|
|
|
let mut args = Vec::new();
|
|
|
|
for arg in arg_operands {
|
|
|
|
let arg_val = self.eval_operand(arg)?;
|
|
|
|
let arg_ty = self.operand_ty(arg);
|
|
|
|
args.push((arg_val, arg_ty));
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
2017-03-22 14:19:29 +01:00
|
|
|
assert_eq!(sig.abi, Abi::RustCall);
|
2017-03-22 13:13:52 +01:00
|
|
|
self.eval_fn_call_inner(
|
|
|
|
instance,
|
|
|
|
destination,
|
|
|
|
args,
|
|
|
|
span,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
ty::InstanceDef::Item(_) => {
|
|
|
|
let mut args = Vec::new();
|
|
|
|
for arg in arg_operands {
|
|
|
|
let arg_val = self.eval_operand(arg)?;
|
|
|
|
let arg_ty = self.operand_ty(arg);
|
|
|
|
args.push((arg_val, arg_ty));
|
|
|
|
}
|
2017-03-22 14:19:29 +01:00
|
|
|
match sig.abi {
|
2017-03-22 16:16:23 +01:00
|
|
|
Abi::C => {
|
|
|
|
let ty = sig.output();
|
|
|
|
let (ret, target) = destination.unwrap();
|
|
|
|
self.call_c_abi(instance.def_id(), arg_operands, ret, ty)?;
|
|
|
|
self.dump_local(ret);
|
|
|
|
self.goto_block(target);
|
|
|
|
return Ok(());
|
|
|
|
},
|
2017-03-22 13:13:52 +01:00
|
|
|
Abi::Rust => {},
|
|
|
|
Abi::RustCall => self.unpack_fn_args(&mut args)?,
|
|
|
|
_ => unimplemented!(),
|
|
|
|
}
|
2017-02-28 12:35:00 +01:00
|
|
|
self.eval_fn_call_inner(
|
2017-03-21 13:53:55 +01:00
|
|
|
instance,
|
2017-02-28 12:35:00 +01:00
|
|
|
destination,
|
|
|
|
args,
|
|
|
|
span,
|
|
|
|
)
|
|
|
|
},
|
2017-03-22 18:31:41 +01:00
|
|
|
ty::InstanceDef::DropGlue(..) => {
|
|
|
|
assert_eq!(arg_operands.len(), 1);
|
|
|
|
assert_eq!(sig.abi, Abi::Rust);
|
|
|
|
let val = self.eval_operand(&arg_operands[0])?;
|
|
|
|
let ty = self.operand_ty(&arg_operands[0]);
|
|
|
|
let (_, target) = destination.expect("diverging drop glue");
|
|
|
|
self.goto_block(target);
|
|
|
|
// FIXME: deduplicate these matches
|
|
|
|
let pointee_type = match ty.sty {
|
|
|
|
ty::TyRawPtr(ref tam) |
|
|
|
|
ty::TyRef(_, ref tam) => tam.ty,
|
|
|
|
ty::TyAdt(ref def, _) if def.is_box() => ty.boxed_ty(),
|
|
|
|
_ => bug!("can only deref pointer types"),
|
|
|
|
};
|
|
|
|
self.drop(val, instance, pointee_type, span)
|
2017-03-23 10:04:08 +01:00
|
|
|
},
|
|
|
|
ty::InstanceDef::FnPtrShim(..) => {
|
|
|
|
let mut args = Vec::new();
|
|
|
|
for arg in arg_operands {
|
|
|
|
let arg_val = self.eval_operand(arg)?;
|
|
|
|
let arg_ty = self.operand_ty(arg);
|
|
|
|
args.push((arg_val, arg_ty));
|
|
|
|
}
|
|
|
|
match sig.abi {
|
|
|
|
Abi::Rust => {
|
|
|
|
args.remove(0);
|
|
|
|
},
|
|
|
|
Abi::RustCall => {},
|
|
|
|
_ => unimplemented!(),
|
|
|
|
}
|
|
|
|
trace!("ABI: {}", sig.abi);
|
|
|
|
self.eval_fn_call_inner(
|
|
|
|
instance,
|
|
|
|
destination,
|
|
|
|
args,
|
|
|
|
span,
|
|
|
|
)
|
2017-03-22 18:31:41 +01:00
|
|
|
}
|
2017-03-22 14:19:29 +01:00
|
|
|
_ => Err(EvalError::Unimplemented(format!("can't handle function with {:?} ABI", sig.abi))),
|
2017-02-28 12:35:00 +01:00
|
|
|
}
|
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2017-02-28 12:35:00 +01:00
|
|
|
fn eval_fn_call_inner(
|
|
|
|
&mut self,
|
2017-03-21 13:53:55 +01:00
|
|
|
instance: ty::Instance<'tcx>,
|
2017-02-28 12:35:00 +01:00
|
|
|
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
|
|
|
|
args: Vec<(Value, Ty<'tcx>)>,
|
|
|
|
span: Span,
|
|
|
|
) -> EvalResult<'tcx> {
|
2017-03-22 13:13:52 +01:00
|
|
|
trace!("eval_fn_call_inner: {:#?}, {:#?}, {:#?}", instance, args, destination);
|
|
|
|
|
|
|
|
// Only trait methods can have a Self parameter.
|
2017-02-28 12:35:00 +01:00
|
|
|
|
2017-03-21 13:53:55 +01:00
|
|
|
let mir = match self.load_mir(instance.def) {
|
2017-02-28 12:35:00 +01:00
|
|
|
Ok(mir) => mir,
|
|
|
|
Err(EvalError::NoMirFor(path)) => {
|
|
|
|
match &path[..] {
|
|
|
|
// let's just ignore all output for now
|
|
|
|
"std::io::_print" => {
|
|
|
|
self.goto_block(destination.unwrap().1);
|
|
|
|
return Ok(());
|
|
|
|
},
|
|
|
|
"std::thread::Builder::new" => return Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
|
|
|
|
"std::env::args" => return Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
|
|
|
|
"std::panicking::rust_panic_with_hook" |
|
|
|
|
"std::rt::begin_panic_fmt" => return Err(EvalError::Panic),
|
|
|
|
"std::panicking::panicking" |
|
|
|
|
"std::rt::panicking" => {
|
|
|
|
let (lval, block) = destination.expect("std::rt::panicking does not diverge");
|
|
|
|
// we abort on panic -> `std::rt::panicking` always returns false
|
|
|
|
let bool = self.tcx.types.bool;
|
|
|
|
self.write_primval(lval, PrimVal::from_bool(false), bool)?;
|
|
|
|
self.goto_block(block);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
return Err(EvalError::NoMirFor(path));
|
|
|
|
},
|
|
|
|
Err(other) => return Err(other),
|
|
|
|
};
|
|
|
|
let (return_lvalue, return_to_block) = match destination {
|
|
|
|
Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
|
|
|
|
None => {
|
|
|
|
// FIXME(solson)
|
|
|
|
let lvalue = Lvalue::from_ptr(Pointer::never_ptr());
|
|
|
|
(lvalue, StackPopCleanup::None)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self.push_stack_frame(
|
2017-03-21 13:53:55 +01:00
|
|
|
instance,
|
2017-02-28 12:35:00 +01:00
|
|
|
span,
|
|
|
|
mir,
|
|
|
|
return_lvalue,
|
|
|
|
return_to_block,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let arg_locals = self.frame().mir.args_iter();
|
|
|
|
assert_eq!(self.frame().mir.arg_count, args.len());
|
|
|
|
for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
|
|
|
|
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
|
|
|
|
self.write_value(arg_val, dest, arg_ty)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
2017-02-28 12:35:00 +01:00
|
|
|
|
|
|
|
Ok(())
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2017-02-24 10:39:55 +01:00
|
|
|
pub fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
|
2016-06-23 01:03:58 -06:00
|
|
|
use rustc::ty::layout::Layout::*;
|
2016-11-17 17:23:40 +01:00
|
|
|
let adt_layout = self.type_layout(adt_ty)?;
|
2017-01-28 15:46:46 +01:00
|
|
|
trace!("read_discriminant_value {:#?}", adt_layout);
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
let discr_val = match *adt_layout {
|
2016-11-05 02:53:02 +00:00
|
|
|
General { discr, .. } | CEnum { discr, signed: false, .. } => {
|
2016-06-23 01:03:58 -06:00
|
|
|
let discr_size = discr.size().bytes();
|
2016-11-18 12:55:14 +01:00
|
|
|
self.memory.read_uint(adt_ptr, discr_size)?
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2016-11-05 02:53:02 +00:00
|
|
|
CEnum { discr, signed: true, .. } => {
|
|
|
|
let discr_size = discr.size().bytes();
|
2017-01-12 08:28:42 +01:00
|
|
|
self.memory.read_int(adt_ptr, discr_size)? as u128
|
2016-11-05 02:53:02 +00:00
|
|
|
}
|
|
|
|
|
2016-11-11 13:10:47 +01:00
|
|
|
RawNullablePointer { nndiscr, value } => {
|
2016-11-18 12:55:14 +01:00
|
|
|
let discr_size = value.size(&self.tcx.data_layout).bytes();
|
2016-11-17 14:48:34 +01:00
|
|
|
trace!("rawnullablepointer with size {}", discr_size);
|
2017-01-12 08:28:42 +01:00
|
|
|
self.read_nonnull_discriminant_value(adt_ptr, nndiscr as u128, discr_size)?
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
|
2016-11-11 13:10:47 +01:00
|
|
|
let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
|
2016-11-18 12:55:14 +01:00
|
|
|
let nonnull = adt_ptr.offset(offset.bytes());
|
2016-11-17 14:48:34 +01:00
|
|
|
trace!("struct wrapped nullable pointer type: {}", ty);
|
2016-11-11 13:10:47 +01:00
|
|
|
// only the pointer part of a fat pointer is used for this space optimization
|
2016-11-17 17:23:40 +01:00
|
|
|
let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
|
2017-01-12 08:28:42 +01:00
|
|
|
self.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size)?
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// The discriminant_value intrinsic returns 0 for non-sum types.
|
|
|
|
Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
|
2016-09-07 10:12:15 +02:00
|
|
|
Vector { .. } | UntaggedUnion { .. } => 0,
|
2016-06-23 01:03:58 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(discr_val)
|
|
|
|
}
|
|
|
|
|
2017-01-12 08:28:42 +01:00
|
|
|
fn read_nonnull_discriminant_value(&self, ptr: Pointer, nndiscr: u128, discr_size: u64) -> EvalResult<'tcx, u128> {
|
2017-01-28 15:46:46 +01:00
|
|
|
trace!("read_nonnull_discriminant_value: {:?}, {}, {}", ptr, nndiscr, discr_size);
|
2016-11-11 13:10:47 +01:00
|
|
|
let not_null = match self.memory.read_uint(ptr, discr_size) {
|
2016-06-23 01:03:58 -06:00
|
|
|
Ok(0) => false,
|
|
|
|
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
|
|
|
|
Err(e) => return Err(e),
|
|
|
|
};
|
|
|
|
assert!(nndiscr == 0 || nndiscr == 1);
|
|
|
|
Ok(if not_null { nndiscr } else { 1 - nndiscr })
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call_c_abi(
|
|
|
|
&mut self,
|
|
|
|
def_id: DefId,
|
|
|
|
args: &[mir::Operand<'tcx>],
|
2016-10-21 10:29:56 +02:00
|
|
|
dest: Lvalue<'tcx>,
|
2016-11-26 22:58:01 -08:00
|
|
|
dest_ty: Ty<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-06-23 01:03:58 -06:00
|
|
|
let name = self.tcx.item_name(def_id);
|
|
|
|
let attrs = self.tcx.get_attrs(def_id);
|
2016-11-26 17:36:31 -08:00
|
|
|
let link_name = attr::first_attr_value_str_by_name(&attrs, "link_name")
|
|
|
|
.unwrap_or(name)
|
|
|
|
.as_str();
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2016-09-23 10:27:14 +02:00
|
|
|
let args_res: EvalResult<Vec<Value>> = args.iter()
|
|
|
|
.map(|arg| self.eval_operand(arg))
|
2016-06-23 01:03:58 -06:00
|
|
|
.collect();
|
|
|
|
let args = args_res?;
|
|
|
|
|
2016-09-23 10:27:14 +02:00
|
|
|
let usize = self.tcx.types.usize;
|
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
match &link_name[..] {
|
|
|
|
"__rust_allocate" => {
|
2016-12-16 22:01:01 -08:00
|
|
|
let size = self.value_to_primval(args[0], usize)?.to_u64()?;
|
|
|
|
let align = self.value_to_primval(args[1], usize)?.to_u64()?;
|
2016-11-18 12:55:14 +01:00
|
|
|
let ptr = self.memory.allocate(size, align)?;
|
2016-12-15 23:55:00 -08:00
|
|
|
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2016-11-03 17:32:06 +01:00
|
|
|
"__rust_deallocate" => {
|
|
|
|
let ptr = args[0].read_ptr(&self.memory)?;
|
|
|
|
// FIXME: insert sanity check for size and align?
|
2016-12-16 22:01:01 -08:00
|
|
|
let _old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
|
|
|
|
let _align = self.value_to_primval(args[2], usize)?.to_u64()?;
|
2016-11-03 17:32:06 +01:00
|
|
|
self.memory.deallocate(ptr)?;
|
|
|
|
},
|
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
"__rust_reallocate" => {
|
2016-09-23 10:27:14 +02:00
|
|
|
let ptr = args[0].read_ptr(&self.memory)?;
|
2016-12-16 22:01:01 -08:00
|
|
|
let size = self.value_to_primval(args[2], usize)?.to_u64()?;
|
|
|
|
let align = self.value_to_primval(args[3], usize)?.to_u64()?;
|
2016-11-18 12:55:14 +01:00
|
|
|
let new_ptr = self.memory.reallocate(ptr, size, align)?;
|
2016-12-15 23:55:00 -08:00
|
|
|
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
"memcmp" => {
|
2016-09-23 10:27:14 +02:00
|
|
|
let left = args[0].read_ptr(&self.memory)?;
|
|
|
|
let right = args[1].read_ptr(&self.memory)?;
|
2016-12-16 22:01:01 -08:00
|
|
|
let n = self.value_to_primval(args[2], usize)?.to_u64()?;
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
let result = {
|
|
|
|
let left_bytes = self.memory.read_bytes(left, n)?;
|
|
|
|
let right_bytes = self.memory.read_bytes(right, n)?;
|
|
|
|
|
|
|
|
use std::cmp::Ordering::*;
|
|
|
|
match left_bytes.cmp(right_bytes) {
|
2017-01-12 08:28:42 +01:00
|
|
|
Less => -1i8,
|
2016-06-23 01:03:58 -06:00
|
|
|
Equal => 0,
|
|
|
|
Greater => 1,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-12 08:28:42 +01:00
|
|
|
self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2017-01-12 09:26:22 +01:00
|
|
|
"memrchr" => {
|
|
|
|
let ptr = args[0].read_ptr(&self.memory)?;
|
2017-01-12 09:30:18 +01:00
|
|
|
let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
|
|
|
|
let num = self.value_to_primval(args[2], usize)?.to_u64()?;
|
2017-01-12 09:26:22 +01:00
|
|
|
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) {
|
|
|
|
let new_ptr = ptr.offset(num - idx as u64 - 1);
|
|
|
|
self.write_value(Value::ByVal(PrimVal::Ptr(new_ptr)), dest, dest_ty)?;
|
|
|
|
} else {
|
|
|
|
self.write_value(Value::ByVal(PrimVal::Bytes(0)), dest, dest_ty)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-16 17:10:16 -08:00
|
|
|
"memchr" => {
|
|
|
|
let ptr = args[0].read_ptr(&self.memory)?;
|
2016-12-16 22:01:01 -08:00
|
|
|
let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
|
|
|
|
let num = self.value_to_primval(args[2], usize)?.to_u64()?;
|
2016-12-16 17:10:16 -08:00
|
|
|
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
|
|
|
|
let new_ptr = ptr.offset(idx as u64);
|
2016-12-16 22:01:01 -08:00
|
|
|
self.write_value(Value::ByVal(PrimVal::Ptr(new_ptr)), dest, dest_ty)?;
|
2016-12-16 17:10:16 -08:00
|
|
|
} else {
|
2016-12-16 22:01:01 -08:00
|
|
|
self.write_value(Value::ByVal(PrimVal::Bytes(0)), dest, dest_ty)?;
|
2016-12-16 17:10:16 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
"getenv" => {
|
|
|
|
{
|
|
|
|
let name_ptr = args[0].read_ptr(&self.memory)?;
|
|
|
|
let name = self.memory.read_c_str(name_ptr)?;
|
|
|
|
info!("ignored env var request for `{:?}`", ::std::str::from_utf8(name));
|
|
|
|
}
|
2016-12-16 22:01:01 -08:00
|
|
|
self.write_value(Value::ByVal(PrimVal::Bytes(0)), dest, dest_ty)?;
|
2016-12-16 17:10:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// unix panic code inside libstd will read the return value of this function
|
|
|
|
"pthread_rwlock_rdlock" => {
|
2016-12-16 22:01:01 -08:00
|
|
|
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
2016-12-16 17:10:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
link_name if link_name.starts_with("pthread_") => {
|
|
|
|
warn!("ignoring C ABI call: {}", link_name);
|
|
|
|
return Ok(());
|
|
|
|
},
|
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
_ => {
|
|
|
|
return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since we pushed no stack frame, the main loop will act
|
|
|
|
// as if the call just completed and it's returning to the
|
|
|
|
// current frame.
|
|
|
|
Ok(())
|
|
|
|
}
|
2017-03-22 13:13:52 +01:00
|
|
|
|
|
|
|
pub(crate) fn unpack_fn_args(&self, args: &mut Vec<(Value, Ty<'tcx>)>) -> EvalResult<'tcx> {
|
|
|
|
if let Some((last, last_ty)) = args.pop() {
|
|
|
|
let last_layout = self.type_layout(last_ty)?;
|
|
|
|
match (&last_ty.sty, last_layout) {
|
|
|
|
(&ty::TyTuple(fields, _),
|
|
|
|
&Layout::Univariant { ref variant, .. }) => {
|
|
|
|
let offsets = variant.offsets.iter().map(|s| s.bytes());
|
|
|
|
match last {
|
|
|
|
Value::ByRef(last_ptr) => {
|
|
|
|
for (offset, ty) in offsets.zip(fields) {
|
|
|
|
let arg = Value::ByRef(last_ptr.offset(offset));
|
|
|
|
args.push((arg, ty));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// propagate undefs
|
|
|
|
undef @ Value::ByVal(PrimVal::Undef) => {
|
|
|
|
for field_ty in fields {
|
|
|
|
args.push((undef, field_ty));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => bug!("rust-call ABI tuple argument was {:?}, but {:?} were expected", last, fields),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2016-09-20 12:52:01 +02:00
|
|
|
}
|