about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs32
-rw-r--r--tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs27
-rw-r--r--tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs2
-rw-r--r--tests/ui/sanitizer/cfi-drop-in-place.rs20
4 files changed, 79 insertions, 2 deletions
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 1c6a0f9cf4d..04b92fbd33b 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -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())
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
new file mode 100644
index 00000000000..3ec1988edd6
--- /dev/null
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs
@@ -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"}
diff --git a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
index f08c9e6702e..f9c7cca3989 100644
--- a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
+++ b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs
@@ -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);
diff --git a/tests/ui/sanitizer/cfi-drop-in-place.rs b/tests/ui/sanitizer/cfi-drop-in-place.rs
new file mode 100644
index 00000000000..8ce2c432602
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-drop-in-place.rs
@@ -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>;
+}