Skip to content

Commit 0b86081

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 Drop trait objects.
1 parent c98ea0d commit 0b86081

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

Diff for: compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -1112,8 +1112,36 @@ pub fn typeid_for_instance<'tcx>(
11121112
mut instance: Instance<'tcx>,
11131113
options: TypeIdOptions,
11141114
) -> String {
1115-
if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
1116-
instance.args = strip_receiver_auto(tcx, instance.args)
1115+
if (matches!(instance.def, ty::InstanceDef::Virtual(..))
1116+
&& Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn())
1117+
|| matches!(instance.def, ty::InstanceDef::DropGlue(..))
1118+
{
1119+
// Adjust the type ids of DropGlues
1120+
//
1121+
// DropGlues may have indirect calls to one or more given types drop function. Rust allows
1122+
// for types to be erased to any trait object and retains the drop function for the original
1123+
// type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is
1124+
// called a second time, it only has information after type erasure and it could be a call
1125+
// on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on
1126+
// declaration/definition, and during code generation at call sites so they have the same
1127+
// type id and match.
1128+
//
1129+
// FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of
1130+
// any other type.
1131+
//
1132+
let def_id = tcx
1133+
.lang_items()
1134+
.drop_trait()
1135+
.unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
1136+
let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef {
1137+
def_id: def_id,
1138+
args: List::empty(),
1139+
});
1140+
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
1141+
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
1142+
instance.args = tcx.mk_args_trait(self_ty, List::empty());
1143+
} else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
1144+
instance.args = strip_receiver_auto(tcx, instance.args);
11171145
}
11181146

11191147
if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Verifies that type metadata identifiers for drop functions are emitted correctly.
2+
//
3+
//@ needs-sanitizer-cfi
4+
//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
5+
6+
#![crate_type="lib"]
7+
8+
// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$
9+
// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
10+
// CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE")
11+
12+
struct EmptyDrop;
13+
// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
14+
15+
struct NonEmptyDrop;
16+
17+
impl Drop for NonEmptyDrop {
18+
fn drop(&mut self) {}
19+
// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}NonEmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
20+
}
21+
22+
pub fn foo() {
23+
let _ = Box::new(EmptyDrop) as Box<dyn Send>;
24+
let _ = Box::new(NonEmptyDrop) as Box<dyn Send>;
25+
}
26+
27+
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"}

Diff for: tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b
2929
trait Freeze { }
3030
#[lang="drop_in_place"]
3131
fn drop_in_place_fn<T>() { }
32+
#[lang="drop"]
33+
trait Drop { fn drop(&mut self); }
3234

3335
pub trait Trait1 {
3436
fn foo(&self);

Diff for: tests/ui/sanitizer/cfi-drop-in-place.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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 EmptyDrop;
10+
11+
struct NonEmptyDrop;
12+
13+
impl Drop for NonEmptyDrop {
14+
fn drop(&mut self) {}
15+
}
16+
17+
fn main() {
18+
let _ = Box::new(EmptyDrop) as Box<dyn Send>;
19+
let _ = Box::new(NonEmptyDrop) as Box<dyn Send>;
20+
}

0 commit comments

Comments
 (0)