Skip to content

Commit

Permalink
Rollup merge of #123075 - rcvalle:rust-cfi-fix-drop-drop-in-place, r=…
Browse files Browse the repository at this point in the history
…compiler-errors

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.

This was split off from #116404.

cc `@compiler-errors` `@workingjubilee`
  • Loading branch information
matthiaskrgr authored Mar 27, 2024
2 parents a9ed9fb + 0b86081 commit 6464e5b
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1112,8 +1112,36 @@ pub fn typeid_for_instance<'tcx>(
mut instance: Instance<'tcx>,
options: TypeIdOptions,
) -> String {
if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
instance.args = strip_receiver_auto(tcx, instance.args)
if (matches!(instance.def, ty::InstanceDef::Virtual(..))
&& Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn())
|| matches!(instance.def, ty::InstanceDef::DropGlue(..))
{
// Adjust the type ids of DropGlues
//
// DropGlues may have indirect calls to one or more given types drop function. Rust allows
// for types to be erased to any trait object and retains the drop function for the original
// type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is
// called a second time, it only has information after type erasure and it could be a call
// on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on
// declaration/definition, and during code generation at call sites so they have the same
// type id and match.
//
// FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of
// any other type.
//
let def_id = tcx
.lang_items()
.drop_trait()
.unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef {
def_id: def_id,
args: List::empty(),
});
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
instance.args = tcx.mk_args_trait(self_ty, List::empty());
} else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
instance.args = strip_receiver_auto(tcx, instance.args);
}

if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Verifies that type metadata identifiers for drop functions are emitted correctly.
//
//@ needs-sanitizer-cfi
//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static

#![crate_type="lib"]

// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$
// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
// CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE")

struct EmptyDrop;
// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}

struct NonEmptyDrop;

impl Drop for NonEmptyDrop {
fn drop(&mut self) {}
// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}NonEmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
}

pub fn foo() {
let _ = Box::new(EmptyDrop) as Box<dyn Send>;
let _ = Box::new(NonEmptyDrop) as Box<dyn Send>;
}

// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b
trait Freeze { }
#[lang="drop_in_place"]
fn drop_in_place_fn<T>() { }
#[lang="drop"]
trait Drop { fn drop(&mut self); }

pub trait Trait1 {
fn foo(&self);
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/sanitizer/cfi-drop-in-place.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Verifies that drops can be called on arbitrary trait objects.
//
// FIXME(#122848): Remove only-linux when fixed.
//@ only-linux
//@ needs-sanitizer-cfi
//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
//@ run-pass

struct EmptyDrop;

struct NonEmptyDrop;

impl Drop for NonEmptyDrop {
fn drop(&mut self) {}
}

fn main() {
let _ = Box::new(EmptyDrop) as Box<dyn Send>;
let _ = Box::new(NonEmptyDrop) as Box<dyn Send>;
}

0 comments on commit 6464e5b

Please sign in to comment.