about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs38
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/intrinsic.rs2
4 files changed, 47 insertions, 3 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 7c25438380a..297dcde99b3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -19,6 +19,7 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
+use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
 use rustc_target::abi::{self, HasDataLayout, WrappingRange};
 use rustc_target::spec::abi::Abi;
@@ -818,12 +819,43 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
         }
 
-        let fn_ptr = match (llfn, instance) {
-            (Some(llfn), _) => llfn,
-            (None, Some(instance)) => bx.get_fn_addr(instance),
+        let (is_indirect_call, fn_ptr) = match (llfn, instance) {
+            (Some(llfn), _) => (true, llfn),
+            (None, Some(instance)) => (false, bx.get_fn_addr(instance)),
             _ => span_bug!(span, "no llfn for call"),
         };
 
+        // For backends that support CFI using type membership (i.e., testing whether a given
+        // pointer is associated with a type identifier).
+        if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
+            // Emit type metadata and checks.
+            // FIXME(rcvalle): Add support for generalized identifiers.
+            // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
+            let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
+            let typeid_metadata = bx.typeid_metadata(typeid.clone());
+
+            // Test whether the function pointer is associated with the type identifier.
+            let cond = bx.type_test(fn_ptr, typeid_metadata);
+            let mut bx_pass = bx.build_sibling_block("type_test.pass");
+            let mut bx_fail = bx.build_sibling_block("type_test.fail");
+            bx.cond_br(cond, bx_pass.llbb(), bx_fail.llbb());
+
+            helper.do_call(
+                self,
+                &mut bx_pass,
+                fn_abi,
+                fn_ptr,
+                &llargs,
+                destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+                cleanup,
+            );
+
+            bx_fail.abort();
+            bx_fail.unreachable();
+
+            return;
+        }
+
         helper.do_call(
             self,
             &mut bx,
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 476ddbd9398..1cd400eecfb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -4,6 +4,7 @@ use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
+use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{FnAbi, PassMode};
 
 use std::iter;
@@ -244,6 +245,13 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     for (bb, _) in traversal::reverse_postorder(&mir) {
         fx.codegen_block(bb);
     }
+
+    // For backends that support CFI using type membership (i.e., testing whether a given  pointer
+    // is associated with a type identifier).
+    if cx.tcx().sess.is_sanitizer_cfi_enabled() {
+        let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
+        bx.type_metadata(llfn, typeid.clone());
+    }
 }
 
 /// Produces, for each argument, a `Value` pointing at the
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index e7da96f0ada..158e658301e 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -158,6 +158,8 @@ pub trait BuilderMethods<'a, 'tcx>:
 
     fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
     fn nonnull_metadata(&mut self, load: Self::Value);
+    fn type_metadata(&mut self, function: Self::Function, typeid: String);
+    fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
 
     fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
     fn store_with_flags(
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index 777436ad2ae..78bf22ef9f2 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -24,6 +24,8 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
     ///
     /// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend.
     fn sideeffect(&mut self);
+    /// Trait method used to test whether a given pointer is associated with a type identifier.
+    fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value;
     /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
     /// Rust defined C-variadic functions.
     fn va_start(&mut self, val: Self::Value) -> Self::Value;