about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-29 09:04:05 +0000
committerbors <bors@rust-lang.org>2024-03-29 09:04:05 +0000
commit58dcd1fdb9a605bd2f0126d1b06ae6511bbc1dab (patch)
treeef2f278c7734ec930daf95340b69771d31ffaa01
parent1c19595575968ea77c7f85e97c67d44d8c0f9a68 (diff)
parent8e6b4e91b68a0921c534aa1174d27f3c6418b1e6 (diff)
downloadrust-58dcd1fdb9a605bd2f0126d1b06ae6511bbc1dab.tar.gz
rust-58dcd1fdb9a605bd2f0126d1b06ae6511bbc1dab.zip
Auto merge of #123071 - rcvalle:rust-cfi-fix-method-fn-ptr-cast, r=compiler-errors
CFI: Fix methods as function pointer cast

Fix casting between methods and function pointers by assigning a secondary type id to methods with their concrete self so they can be used as function pointers.

This was split off from #116404.

cc `@compiler-errors` `@workingjubilee`
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs52
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs11
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs3
-rw-r--r--tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs22
-rw-r--r--tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs23
5 files changed, 84 insertions, 27 deletions
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 1a2498c75a7..3ef8538ced3 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -18,7 +18,9 @@ use crate::llvm;
 use crate::llvm::AttributePlace::Function;
 use crate::type_::Type;
 use crate::value::Value;
+use itertools::Itertools;
 use rustc_codegen_ssa::traits::TypeMembershipMethods;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::ty::{Instance, Ty};
 use rustc_symbol_mangling::typeid::{
     kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
@@ -141,33 +143,31 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
         if self.tcx.sess.is_sanitizer_cfi_enabled() {
             if let Some(instance) = instance {
-                let typeid = typeid_for_instance(self.tcx, instance, TypeIdOptions::empty());
-                self.set_type_metadata(llfn, typeid);
-                let typeid =
-                    typeid_for_instance(self.tcx, instance, TypeIdOptions::GENERALIZE_POINTERS);
-                self.add_type_metadata(llfn, typeid);
-                let typeid =
-                    typeid_for_instance(self.tcx, instance, TypeIdOptions::NORMALIZE_INTEGERS);
-                self.add_type_metadata(llfn, typeid);
-                let typeid = typeid_for_instance(
-                    self.tcx,
-                    instance,
-                    TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
-                );
-                self.add_type_metadata(llfn, typeid);
+                let mut typeids = FxIndexSet::default();
+                for options in [
+                    TypeIdOptions::GENERALIZE_POINTERS,
+                    TypeIdOptions::NORMALIZE_INTEGERS,
+                    TypeIdOptions::NO_SELF_TYPE_ERASURE,
+                ]
+                .into_iter()
+                .powerset()
+                .map(TypeIdOptions::from_iter)
+                {
+                    let typeid = typeid_for_instance(self.tcx, instance, options);
+                    if typeids.insert(typeid.clone()) {
+                        self.add_type_metadata(llfn, typeid);
+                    }
+                }
             } else {
-                let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
-                self.set_type_metadata(llfn, typeid);
-                let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS);
-                self.add_type_metadata(llfn, typeid);
-                let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS);
-                self.add_type_metadata(llfn, typeid);
-                let typeid = typeid_for_fnabi(
-                    self.tcx,
-                    fn_abi,
-                    TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
-                );
-                self.add_type_metadata(llfn, typeid);
+                for options in
+                    [TypeIdOptions::GENERALIZE_POINTERS, TypeIdOptions::NORMALIZE_INTEGERS]
+                        .into_iter()
+                        .powerset()
+                        .map(TypeIdOptions::from_iter)
+                {
+                    let typeid = typeid_for_fnabi(self.tcx, fn_abi, options);
+                    self.add_type_metadata(llfn, typeid);
+                }
             }
         }
 
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
index 1d28d2b732f..fc1e8e46e8d 100644
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -13,9 +13,20 @@ bitflags! {
     /// Options for typeid_for_fnabi.
     #[derive(Clone, Copy, Debug)]
     pub struct TypeIdOptions: u32 {
+        /// Generalizes pointers for compatibility with Clang
+        /// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI
+        /// support.
         const GENERALIZE_POINTERS = 1;
+        /// Generalizes repr(C) user-defined type for extern function types with the "C" calling
+        /// convention (or extern types) for cross-language LLVM CFI and  KCFI support.
         const GENERALIZE_REPR_C = 2;
+        /// Normalizes integers for compatibility with Clang
+        /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM
+        /// CFI and  KCFI support.
         const NORMALIZE_INTEGERS = 4;
+        /// Do not perform self type erasure for attaching a secondary type id to methods with their
+        /// concrete self so they can be used as function pointers.
+        const NO_SELF_TYPE_ERASURE = 8;
     }
 }
 
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 04b92fbd33b..7fd5cfeb48b 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
@@ -1144,7 +1144,8 @@ pub fn typeid_for_instance<'tcx>(
         instance.args = strip_receiver_auto(tcx, instance.args);
     }
 
-    if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
+    if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE)
+        && let Some(impl_id) = tcx.impl_of_method(instance.def_id())
         && let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
     {
         let impl_method = tcx.associated_item(instance.def_id());
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
new file mode 100644
index 00000000000..671db563dde
--- /dev/null
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs
@@ -0,0 +1,22 @@
+// Verifies that a secondary type metadata identifier is assigned to methods with their concrete
+// self so they can be used as function pointers.
+//
+//@ needs-sanitizer-cfi
+//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
+
+#![crate_type="lib"]
+
+trait Trait1 {
+    fn foo(&self);
+}
+
+struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+    // CHECK: define{{.*}}3foo{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
+}
+
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
new file mode 100644
index 00000000000..273b8785fae
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
@@ -0,0 +1,23 @@
+// Verifies that casting a method to a function pointer works.
+//
+// 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
+
+trait Trait1 {
+    fn foo(&self);
+}
+
+struct Type1;
+
+impl Trait1 for Type1 {
+    fn foo(&self) {}
+}
+
+fn main() {
+    let type1 = Type1 {};
+    let f = <Type1 as Trait1>::foo;
+    f(&type1);
+}