Skip to content

Commit a676408

Browse files
committed
CFI: Fix drop and drop_in_place
Fix drop and drop_in_place by transforming self of drop and drop_in_place methods into a Drop trait objects for types that have a non-empty DropGlue.
1 parent c98ea0d commit a676408

File tree

2 files changed

+71
-2
lines changed

2 files changed

+71
-2
lines changed

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+55-2
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,19 @@ fn encode_ty<'tcx>(
745745
typeid
746746
}
747747

748+
/// Creates a trait object.
749+
#[inline]
750+
fn new_dynamic_trait<'tcx>(
751+
tcx: TyCtxt<'tcx>,
752+
def_id: DefId,
753+
args: GenericArgsRef<'tcx>,
754+
) -> Ty<'tcx> {
755+
let predicate =
756+
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id: def_id, args: args });
757+
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
758+
Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn)
759+
}
760+
748761
/// Transforms predicates for being encoded and used in the substitution dictionary.
749762
fn transform_predicates<'tcx>(
750763
tcx: TyCtxt<'tcx>,
@@ -1112,8 +1125,48 @@ pub fn typeid_for_instance<'tcx>(
11121125
mut instance: Instance<'tcx>,
11131126
options: TypeIdOptions,
11141127
) -> String {
1115-
if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
1116-
instance.args = strip_receiver_auto(tcx, instance.args)
1128+
if (matches!(instance.def, ty::InstanceDef::Virtual(..))
1129+
&& instance.def_id() == tcx.lang_items().drop_in_place_fn().unwrap())
1130+
|| matches!(instance.def, ty::InstanceDef::DropGlue(_, Some(_ty)))
1131+
{
1132+
// Adjust the type ids of DropGlues
1133+
//
1134+
// DropGlues may have indirect calls to one or more given types drop function. Rust allows
1135+
// for types to be erased to any trait object and retains the drop function for the original
1136+
// type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is
1137+
// called a second time, it only has information after type erasure and it could be a call
1138+
// on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on
1139+
// declaration/definition, and during code generation at call sites so they have the same
1140+
// type id and match.
1141+
//
1142+
// FIXME(rcvalle): This allows a drop call on any trait object of types that have a
1143+
// non-empty DropGlue to call the DropGlue of any other types that have a non-empty
1144+
// DropGlue.
1145+
let fn_abi = tcx
1146+
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
1147+
.unwrap_or_else(|instance| {
1148+
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
1149+
});
1150+
let self_ty = if fn_abi.args[0].layout.ty.is_mutable_ptr() {
1151+
Ty::new_mut_ref(
1152+
tcx,
1153+
tcx.lifetimes.re_erased,
1154+
new_dynamic_trait(tcx, tcx.lang_items().drop_trait().unwrap(), List::empty()),
1155+
)
1156+
} else {
1157+
Ty::new_imm_ref(
1158+
tcx,
1159+
tcx.lifetimes.re_erased,
1160+
new_dynamic_trait(tcx, tcx.lang_items().drop_trait().unwrap(), List::empty()),
1161+
)
1162+
};
1163+
// HACK(rcvalle): It is okay to not replace or update the entire ArgAbi here because the
1164+
// other fields are never used.
1165+
let mut fn_abi = fn_abi.clone();
1166+
fn_abi.args[0].layout.ty = self_ty;
1167+
return typeid_for_fnabi(tcx, &fn_abi, options);
1168+
} else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
1169+
instance.args = strip_receiver_auto(tcx, instance.args);
11171170
}
11181171

11191172
if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Verifies that drops can be called on arbitrary trait objects.
2+
//
3+
// FIXME(#122848): Remove only-linux when fixed.
4+
//@ only-linux
5+
//@ needs-sanitizer-cfi
6+
//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
7+
//@ run-pass
8+
9+
struct CustomDrop;
10+
impl Drop for CustomDrop {
11+
fn drop(&mut self) {}
12+
}
13+
14+
fn main() {
15+
let _ = Box::new(CustomDrop) as Box<dyn Send>;
16+
}

0 commit comments

Comments
 (0)