Merge pull request #610 from RalfJung/panic

Support panic_impl and atomic_nand
This commit is contained in:
Ralf Jung 2019-02-06 13:55:17 +01:00 committed by GitHub
commit 2d4ebf017d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 20 deletions

View File

@ -39,12 +39,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
if this.tcx.is_foreign_item(instance.def_id()) { if this.tcx.is_foreign_item(instance.def_id()) {
// An external function that we cannot find MIR for, but we can still run enough // An external function that we cannot find MIR for, but we can still run enough
// of them to make miri viable. // of them to make miri viable.
this.emulate_foreign_item( this.emulate_foreign_item(instance.def_id(), args, dest, ret)?;
instance.def_id(),
args,
dest.unwrap(),
ret.unwrap(),
)?;
// `goto_block` already handled // `goto_block` already handled
return Ok(None); return Ok(None);
} }
@ -59,8 +54,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
&mut self, &mut self,
def_id: DefId, def_id: DefId,
args: &[OpTy<'tcx, Borrow>], args: &[OpTy<'tcx, Borrow>],
dest: PlaceTy<'tcx, Borrow>, dest: Option<PlaceTy<'tcx, Borrow>>,
ret: mir::BasicBlock, ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx> { ) -> EvalResult<'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
let attrs = this.tcx.get_attrs(def_id); let attrs = this.tcx.get_attrs(def_id);
@ -70,9 +65,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
}; };
// Strip linker suffixes (seen on 32bit macOS) // Strip linker suffixes (seen on 32bit macOS)
let link_name = link_name.trim_end_matches("$UNIX2003"); let link_name = link_name.trim_end_matches("$UNIX2003");
let tcx = &{this.tcx.tcx}; let tcx = &{this.tcx.tcx};
// first: functions that could diverge
match &link_name[..] {
"__rust_start_panic" | "panic_impl" => {
return err!(MachineError("the evaluated program panicked".to_string()));
}
_ => if dest.is_none() {
return err!(Unimplemented(
format!("can't call diverging foreign function: {}", link_name),
));
}
}
// now: functions that assume a ret and dest
let dest = dest.expect("we already checked for a dest");
let ret = ret.expect("dest is Some but ret is None");
match &link_name[..] { match &link_name[..] {
"malloc" => { "malloc" => {
let size = this.read_scalar(args[0])?.to_usize(this)?; let size = this.read_scalar(args[0])?.to_usize(this)?;
@ -245,9 +254,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
return Ok(()); return Ok(());
} }
"__rust_start_panic" =>
return err!(MachineError("the evaluated program panicked".to_string())),
"memcmp" => { "memcmp" => {
let left = this.read_scalar(args[0])?.not_undef()?; let left = this.read_scalar(args[0])?.not_undef()?;
let right = this.read_scalar(args[1])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?;

View File

@ -108,6 +108,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
"atomic_and_rel" | "atomic_and_rel" |
"atomic_and_acqrel" | "atomic_and_acqrel" |
"atomic_and_relaxed" | "atomic_and_relaxed" |
"atomic_nand" |
"atomic_nand_acq" |
"atomic_nand_rel" |
"atomic_nand_acqrel" |
"atomic_nand_relaxed" |
"atomic_xadd" | "atomic_xadd" |
"atomic_xadd_acq" | "atomic_xadd_acq" |
"atomic_xadd_rel" | "atomic_xadd_rel" |
@ -125,16 +130,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
let rhs = this.read_immediate(args[1])?; let rhs = this.read_immediate(args[1])?;
let old = this.read_immediate(ptr.into())?; let old = this.read_immediate(ptr.into())?;
this.write_immediate(*old, dest)?; // old value is returned this.write_immediate(*old, dest)?; // old value is returned
let op = match intrinsic_name.split('_').nth(1).unwrap() { let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() {
"or" => mir::BinOp::BitOr, "or" => (mir::BinOp::BitOr, false),
"xor" => mir::BinOp::BitXor, "xor" => (mir::BinOp::BitXor, false),
"and" => mir::BinOp::BitAnd, "and" => (mir::BinOp::BitAnd, false),
"xadd" => mir::BinOp::Add, "xadd" => (mir::BinOp::Add, false),
"xsub" => mir::BinOp::Sub, "xsub" => (mir::BinOp::Sub, false),
"nand" => (mir::BinOp::BitAnd, true),
_ => bug!(), _ => bug!(),
}; };
// Atomics wrap around on overflow. // Atomics wrap around on overflow.
this.binop_ignore_overflow(op, old, rhs, ptr.into())?; let (val, _overflowed) = this.binary_op_imm(op, old, rhs)?;
let val = if neg {
this.unary_op(mir::UnOp::Not, val, old.layout)?
} else {
val
};
this.write_scalar(val, ptr.into())?;
} }
"breakpoint" => unimplemented!(), // halt miri "breakpoint" => unimplemented!(), // halt miri

View File

@ -1,5 +1,5 @@
//error-pattern: the evaluated program panicked //error-pattern: the evaluated program panicked
fn main() { fn main() {
assert_eq!(5, 6); std::panic!("panicking from libstd");
} }

View File

@ -0,0 +1,5 @@
//error-pattern: the evaluated program panicked
fn main() {
std::panic!("{}-panicking from libstd", 42);
}

View File

@ -0,0 +1,5 @@
//error-pattern: the evaluated program panicked
fn main() {
core::panic!("panicking from libcore");
}

View File

@ -0,0 +1,5 @@
//error-pattern: the evaluated program panicked
fn main() {
core::panic!("{}-panicking from libcore", 42);
}