Move the callee "can unwind" check to the right place

This commit is contained in:
hyd-dev 2021-05-22 03:53:00 +08:00
parent 7b3e10c751
commit da0abad492
No known key found for this signature in database
GPG key ID: 74FA7FD5B8DA14B8
2 changed files with 37 additions and 38 deletions

View file

@ -819,19 +819,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
StackPopCleanup::Goto { ret, unwind } => ( StackPopCleanup::Goto { ret, unwind } => (
true, true,
Some(if unwinding { Some(if unwinding {
let def_id = frame.body.source.def_id();
match unwind { match unwind {
StackPopUnwind::Cleanup(unwind) StackPopUnwind::Cleanup(unwind) => unwind,
// `fn_sig()` can't be used on closures, but closures always have StackPopUnwind::NotAllowed => {
// "rust-call" ABI, which always allows unwinding anyway.
if self.tcx.is_closure(def_id) || self.fn_can_unwind(
self.tcx.codegen_fn_attrs(def_id).flags,
self.tcx.fn_sig(def_id).abi(),
) =>
{
unwind
}
_ => {
throw_ub_format!("unwind past a frame that does not allow unwinding") throw_ub_format!("unwind past a frame that does not allow unwinding")
} }
} }

View file

@ -17,7 +17,7 @@ use super::{
}; };
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
pub(super) fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool { fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
layout::fn_can_unwind( layout::fn_can_unwind(
self.tcx.sess.panic_strategy(), self.tcx.sess.panic_strategy(),
attrs, attrs,
@ -247,37 +247,38 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
}; };
let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
ty::Closure(..) => Abi::RustCall,
ty::Generator(..) => Abi::Rust,
_ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
};
// ABI check // ABI check
let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> { let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
if M::enforce_abi(this) { let normalize_abi = |abi| match abi {
let callee_abi = match instance_ty.kind() { Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), // These are all the same ABI, really.
ty::Closure(..) => Abi::RustCall, {
ty::Generator(..) => Abi::Rust, Abi::Rust
_ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
};
let normalize_abi = |abi| match abi {
Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
// These are all the same ABI, really.
{
Abi::Rust
}
abi => abi,
};
if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
throw_ub_format!(
"calling a function with ABI {} using caller ABI {}",
callee_abi.name(),
caller_abi.name()
)
} }
abi => abi,
};
if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
throw_ub_format!(
"calling a function with ABI {} using caller ABI {}",
callee_abi.name(),
caller_abi.name()
)
} }
Ok(()) Ok(())
}; };
match instance.def { match instance.def {
ty::InstanceDef::Intrinsic(..) => { ty::InstanceDef::Intrinsic(..) => {
check_abi(self, instance.ty(*self.tcx, self.param_env))?; if M::enforce_abi(self) {
check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?;
}
assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
M::call_intrinsic(self, instance, args, ret, unwind) M::call_intrinsic(self, instance, args, ret, unwind)
} }
@ -298,7 +299,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Check against the ABI of the MIR body we are calling (not the ABI of `instance`; // Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
// these can differ when `find_mir_or_eval_fn` does something clever like resolve // these can differ when `find_mir_or_eval_fn` does something clever like resolve
// exported symbol names). // exported symbol names).
check_abi(self, self.tcx.type_of(body.source.def_id()))?; let callee_def_id = body.source.def_id();
let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id));
if M::enforce_abi(self) {
check_abi(callee_abi)?;
}
let callee_can_unwind =
self.fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi);
self.push_stack_frame( self.push_stack_frame(
instance, instance,
@ -306,7 +315,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ret.map(|p| p.0), ret.map(|p| p.0),
StackPopCleanup::Goto { StackPopCleanup::Goto {
ret: ret.map(|p| p.1), ret: ret.map(|p| p.1),
unwind: if can_unwind { unwind: if can_unwind && callee_can_unwind {
StackPopUnwind::Cleanup(unwind) StackPopUnwind::Cleanup(unwind)
} else { } else {
StackPopUnwind::NotAllowed StackPopUnwind::NotAllowed