Skip to content

Commit f388dab

Browse files
committed
CFI: Support function pointers for trait methods
Adds support for both CFI and KCFI for attaching concrete and abstract types to functions. KCFI does this through generation of `ReifyShim` on any function pointer that could go in a vtable, and checking the `ReifyReason` when emitting the instance. CFI does this by attaching both the concrete and abstract type to every instance. Fixes #115953
1 parent 2292393 commit f388dab

File tree

4 files changed

+32
-15
lines changed

4 files changed

+32
-15
lines changed

compiler/rustc_codegen_llvm/src/declare.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::llvm;
1818
use crate::llvm::AttributePlace::Function;
1919
use crate::type_::Type;
2020
use crate::value::Value;
21+
use itertools::Itertools;
2122
use rustc_codegen_ssa::traits::TypeMembershipMethods;
2223
use rustc_middle::ty::{Instance, Ty};
2324
use rustc_symbol_mangling::typeid::{
@@ -143,18 +144,18 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
143144
if let Some(instance) = instance {
144145
let typeid = typeid_for_instance(self.tcx, &instance, TypeIdOptions::empty());
145146
self.set_type_metadata(llfn, typeid);
146-
let typeid =
147-
typeid_for_instance(self.tcx, &instance, TypeIdOptions::GENERALIZE_POINTERS);
148-
self.add_type_metadata(llfn, typeid);
149-
let typeid =
150-
typeid_for_instance(self.tcx, &instance, TypeIdOptions::NORMALIZE_INTEGERS);
151-
self.add_type_metadata(llfn, typeid);
152-
let typeid = typeid_for_instance(
153-
self.tcx,
154-
&instance,
155-
TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
156-
);
157-
self.add_type_metadata(llfn, typeid);
147+
for options in [
148+
TypeIdOptions::GENERALIZE_POINTERS,
149+
TypeIdOptions::NORMALIZE_INTEGERS,
150+
TypeIdOptions::CONCRETE,
151+
]
152+
.into_iter()
153+
.powerset()
154+
.map(TypeIdOptions::from_iter)
155+
{
156+
let typeid = typeid_for_instance(self.tcx, &instance, options);
157+
self.add_type_metadata(llfn, typeid);
158+
}
158159
} else {
159160
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
160161
self.set_type_metadata(llfn, typeid);

compiler/rustc_middle/src/ty/instance.rs

+8
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,14 @@ impl<'tcx> Instance<'tcx> {
502502
debug!(" => fn pointer created for virtual call");
503503
resolved.def = InstanceDef::ReifyShim(def_id, reason);
504504
}
505+
// FIXME(maurer) only shim it if it is a vtable-safe function
506+
_ if tcx.sess.is_sanitizer_kcfi_enabled()
507+
&& tcx.associated_item(def_id).trait_item_def_id.is_some() =>
508+
{
509+
// If this function could also go in a vtable, we need to `ReifyShim` it with
510+
// KCFI because it can only attach one type per function.
511+
resolved.def = InstanceDef::ReifyShim(resolved.def_id(), reason)
512+
}
505513
_ => {}
506514
}
507515

compiler/rustc_symbol_mangling/src/typeid.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
55
/// see design document in the tracking issue #89653.
66
use bitflags::bitflags;
7-
use rustc_middle::ty::{Instance, Ty, TyCtxt};
7+
use rustc_middle::ty::{Instance, InstanceDef, Ty, TyCtxt};
88
use rustc_target::abi::call::FnAbi;
99
use std::hash::Hasher;
1010
use twox_hash::XxHash64;
@@ -16,6 +16,8 @@ bitflags! {
1616
const GENERALIZE_POINTERS = 1;
1717
const GENERALIZE_REPR_C = 2;
1818
const NORMALIZE_INTEGERS = 4;
19+
// Only relevant for `typeid_for_instance`
20+
const CONCRETE = 8;
1921
}
2022
}
2123

@@ -56,8 +58,13 @@ pub fn kcfi_typeid_for_fnabi<'tcx>(
5658
pub fn kcfi_typeid_for_instance<'tcx>(
5759
tcx: TyCtxt<'tcx>,
5860
instance: &Instance<'tcx>,
59-
options: TypeIdOptions,
61+
mut options: TypeIdOptions,
6062
) -> u32 {
63+
// If we receive a `ReifyShim` intended to produce a function pointer, we need to remain
64+
// concrete - abstraction is for vtables.
65+
if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) {
66+
options |= TypeIdOptions::CONCRETE
67+
}
6168
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
6269
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
6370
let mut hash: XxHash64 = Default::default();

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,8 @@ pub fn typeid_for_instance<'tcx>(
11161116
instance.args = strip_receiver_auto(tcx, instance.args)
11171117
}
11181118

1119-
if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
1119+
if !options.contains(TypeIdOptions::CONCRETE)
1120+
&& let Some(impl_id) = tcx.impl_of_method(instance.def_id())
11201121
&& let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
11211122
{
11221123
let impl_method = tcx.associated_item(instance.def_id());

0 commit comments

Comments
 (0)