Auto merge of #1077 - RalfJung:unwind_to_block, r=RalfJung
adjust for goto_block refactoring The Miri side of https://github.com/rust-lang/rust/pull/66646
This commit is contained in:
commit
3bf51f591f
@ -1 +1 @@
|
||||
bd816fd76f4f7a040ca7ac8ca5bc556d761f96fa
|
||||
809e180a76ce97340bf4354ff357bc59e3ca40b2
|
||||
|
14
src/eval.rs
14
src/eval.rs
@ -201,16 +201,18 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
|
||||
// Process the result.
|
||||
match res {
|
||||
Ok(return_code) => {
|
||||
let leaks = ecx.memory.leak_report();
|
||||
// Disable the leak test on some platforms where we do not
|
||||
// correctly implement TLS destructors.
|
||||
let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase();
|
||||
let ignore_leaks = target_os == "windows" || target_os == "macos";
|
||||
if !ignore_leaks && leaks != 0 {
|
||||
tcx.sess.err("the evaluated program leaked memory");
|
||||
// Ignore the provided return code - let the reported error
|
||||
// determine the return code.
|
||||
return None;
|
||||
if !ignore_leaks {
|
||||
let leaks = ecx.memory.leak_report();
|
||||
if leaks != 0 {
|
||||
tcx.sess.err("the evaluated program leaked memory");
|
||||
// Ignore the provided return code - let the reported error
|
||||
// determine the return code.
|
||||
return None;
|
||||
}
|
||||
}
|
||||
return Some(return_code)
|
||||
}
|
||||
|
@ -186,11 +186,10 @@ fn find_fn(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: Option<PlaceTy<'tcx, Tag>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
unwind: Option<mir::BasicBlock>,
|
||||
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
|
||||
ecx.find_fn(instance, args, dest, ret, unwind)
|
||||
ecx.find_fn(instance, args, ret, unwind)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -198,10 +197,10 @@ fn call_extra_fn(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
fn_val: Dlsym,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: Option<PlaceTy<'tcx, Tag>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
_unwind: Option<mir::BasicBlock>,
|
||||
) -> InterpResult<'tcx> {
|
||||
ecx.call_dlsym(fn_val, args, dest, ret)
|
||||
ecx.call_dlsym(fn_val, args, ret)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -210,11 +209,10 @@ fn call_intrinsic(
|
||||
span: Span,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: Option<PlaceTy<'tcx, Tag>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
unwind: Option<mir::BasicBlock>,
|
||||
) -> InterpResult<'tcx> {
|
||||
ecx.call_intrinsic(span, instance, args, dest, ret, unwind)
|
||||
ecx.call_intrinsic(span, instance, args, ret, unwind)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -27,15 +27,12 @@ fn call_dlsym(
|
||||
&mut self,
|
||||
dlsym: Dlsym,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: Option<PlaceTy<'tcx, Tag>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
) -> InterpResult<'tcx> {
|
||||
use self::Dlsym::*;
|
||||
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let dest = dest.expect("we don't support any diverging dlsym");
|
||||
let ret = ret.expect("dest is `Some` but ret is `None`");
|
||||
let (dest, ret) = ret.expect("we don't support any diverging dlsym");
|
||||
|
||||
match dlsym {
|
||||
GetEntropy => {
|
||||
@ -46,8 +43,8 @@ fn call_dlsym(
|
||||
}
|
||||
}
|
||||
|
||||
this.goto_block(Some(ret))?;
|
||||
this.dump_place(*dest);
|
||||
this.go_to_block(ret);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -114,8 +114,7 @@ fn emulate_foreign_item(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: Option<PlaceTy<'tcx, Tag>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
_unwind: Option<mir::BasicBlock>
|
||||
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
|
||||
let this = self.eval_context_mut();
|
||||
@ -129,7 +128,7 @@ fn emulate_foreign_item(
|
||||
let tcx = &{ this.tcx.tcx };
|
||||
|
||||
// First: functions that diverge.
|
||||
match link_name {
|
||||
let (dest, ret) = match link_name {
|
||||
// Note that this matches calls to the *foreign* item `__rust_start_panic* -
|
||||
// that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`.
|
||||
// We forward this to the underlying *implementation* in the panic runtime crate.
|
||||
@ -154,15 +153,15 @@ fn emulate_foreign_item(
|
||||
return Err(InterpError::Exit(code).into());
|
||||
}
|
||||
_ => {
|
||||
if dest.is_none() {
|
||||
if let Some(p) = ret {
|
||||
p
|
||||
} else {
|
||||
throw_unsup_format!("can't call (diverging) foreign function: {}", link_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Next: 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`");
|
||||
// Next: functions that return.
|
||||
match link_name {
|
||||
"malloc" => {
|
||||
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
|
||||
@ -928,8 +927,8 @@ fn emulate_foreign_item(
|
||||
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
|
||||
}
|
||||
|
||||
this.goto_block(Some(ret))?;
|
||||
this.dump_place(*dest);
|
||||
this.go_to_block(ret);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,11 @@ fn call_intrinsic(
|
||||
span: Span,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: Option<PlaceTy<'tcx, Tag>>,
|
||||
_ret: Option<mir::BasicBlock>,
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
unwind: Option<mir::BasicBlock>
|
||||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
if this.emulate_intrinsic(span, instance, args, dest)? {
|
||||
if this.emulate_intrinsic(span, instance, args, ret)? {
|
||||
return Ok(());
|
||||
}
|
||||
let tcx = &{this.tcx.tcx};
|
||||
@ -32,23 +31,21 @@ fn call_intrinsic(
|
||||
// that might still hang around!
|
||||
let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str();
|
||||
|
||||
// Handle diverging intrinsics
|
||||
match intrinsic_name {
|
||||
// Handle diverging intrinsics.
|
||||
let (dest, ret) = match intrinsic_name {
|
||||
"abort" => {
|
||||
// FIXME: Add a better way of indicating 'abnormal' termination,
|
||||
// since this is not really an 'unsupported' behavior
|
||||
throw_unsup_format!("the evaluated program aborted!");
|
||||
}
|
||||
"miri_start_panic" => return this.handle_miri_start_panic(args, unwind),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Handle non-diverging intrinsics
|
||||
// The intrinsic itself cannot diverge (otherwise, we would have handled it above),
|
||||
// so if we got here without a return place that's UB (can happen e.g., for transmute returning `!`).
|
||||
let dest = match dest {
|
||||
Some(dest) => dest,
|
||||
None => throw_ub!(Unreachable)
|
||||
_ => {
|
||||
if let Some(p) = ret {
|
||||
p
|
||||
} else {
|
||||
throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match intrinsic_name {
|
||||
@ -581,6 +578,8 @@ fn call_intrinsic(
|
||||
name => throw_unsup_format!("unimplemented intrinsic: {}", name),
|
||||
}
|
||||
|
||||
this.dump_place(*dest);
|
||||
this.go_to_block(ret);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -16,25 +16,24 @@ fn find_fn(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, Tag>],
|
||||
dest: Option<PlaceTy<'tcx, Tag>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
|
||||
unwind: Option<mir::BasicBlock>
|
||||
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
|
||||
let this = self.eval_context_mut();
|
||||
trace!(
|
||||
"eval_fn_call: {:#?}, {:?}",
|
||||
instance,
|
||||
dest.map(|place| *place)
|
||||
ret.map(|p| *p.0)
|
||||
);
|
||||
|
||||
// There are some more lang items we want to hook that CTFE does not hook (yet).
|
||||
if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
|
||||
let dest = dest.unwrap();
|
||||
let (dest, ret) = ret.unwrap();
|
||||
let n = this
|
||||
.align_offset(args[0], args[1])?
|
||||
.unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout));
|
||||
this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
|
||||
this.goto_block(ret)?;
|
||||
this.go_to_block(ret);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
@ -46,7 +45,7 @@ fn find_fn(
|
||||
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
|
||||
// foreign function
|
||||
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
|
||||
return this.emulate_foreign_item(instance.def_id(), args, dest, ret, unwind);
|
||||
return this.emulate_foreign_item(instance.def_id(), args, ret, unwind);
|
||||
}
|
||||
|
||||
// Otherwise, load the MIR.
|
||||
|
@ -53,10 +53,7 @@ fn handle_miri_start_panic(
|
||||
this.machine.panic_payload = Some(scalar);
|
||||
|
||||
// Jump to the unwind block to begin unwinding.
|
||||
// We don't use `goto_block` as that is just meant for normal returns.
|
||||
let next_frame = this.frame_mut();
|
||||
next_frame.block = unwind;
|
||||
next_frame.stmt = 0;
|
||||
this.unwind_to_block(unwind);
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user