Skip to content

Commit df8c3a8

Browse files
committed
CFI: Fix (3) of core and std have explict CFI violations
Fixes (3) of #115199 by transforming function items, closures, and Fn trait objects into function pointers.
1 parent 07a4b7e commit df8c3a8

8 files changed

+552
-583
lines changed

compiler/rustc_middle/src/ty/sty.rs

+62
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,52 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
744744
}
745745

746746
impl<'tcx> List<ty::PolyExistentialPredicate<'tcx>> {
747+
/// Returns the list of arguments if principal is an Fn trait.
748+
pub fn fn_trait_args(&self, tcx: TyCtxt<'tcx>) -> Option<&List<Ty<'tcx>>> {
749+
if self.is_fn_trait(tcx) {
750+
if let Some(args) = self.principal_args() && !args.is_empty() && args[0].expect_ty().is_tuple() {
751+
Some(args[0].expect_ty().tuple_fields())
752+
} else {
753+
Some(List::empty())
754+
}
755+
} else {
756+
None
757+
}
758+
}
759+
760+
/// Returns the output if principal is an Fn trait.
761+
pub fn fn_trait_output(&self, tcx: TyCtxt<'tcx>) -> Option<Ty<'tcx>> {
762+
if self.is_fn_trait(tcx) {
763+
if let Some(projection) = self.projection_bounds().next() && let Some(ty) = projection.skip_binder().term.ty() {
764+
Some(ty)
765+
} else {
766+
Some(Ty::new_unit(tcx))
767+
}
768+
} else {
769+
None
770+
}
771+
}
772+
773+
/// Returns the signature if principal is an Fn trait.
774+
pub fn fn_trait_sig(&self, tcx: TyCtxt<'tcx>) -> Option<FnSig<'tcx>> {
775+
if self.is_fn_trait(tcx) {
776+
Some(tcx.mk_fn_sig(
777+
self.fn_trait_args(tcx).unwrap(),
778+
self.fn_trait_output(tcx).unwrap(),
779+
false,
780+
hir::Unsafety::Normal,
781+
Abi::Rust,
782+
))
783+
} else {
784+
None
785+
}
786+
}
787+
788+
/// Returns true if principal is an Fn trait.
789+
pub fn is_fn_trait(&self, tcx: TyCtxt<'tcx>) -> bool {
790+
if let Some(principal) = self.principal() && tcx.is_fn_trait(principal.skip_binder().def_id) { true } else { false }
791+
}
792+
747793
/// Returns the "principal `DefId`" of this set of existential predicates.
748794
///
749795
/// A Rust trait object type consists (in addition to a lifetime bound)
@@ -778,6 +824,12 @@ impl<'tcx> List<ty::PolyExistentialPredicate<'tcx>> {
778824
.transpose()
779825
}
780826

827+
/// Returns the principal list of arguments.
828+
pub fn principal_args(&self) -> Option<&List<GenericArg<'tcx>>> {
829+
self.principal().map(|trait_ref| trait_ref.skip_binder().args)
830+
}
831+
832+
/// Returns the principal DefId.
781833
pub fn principal_def_id(&self) -> Option<DefId> {
782834
self.principal().map(|trait_ref| trait_ref.skip_binder().def_id)
783835
}
@@ -2269,6 +2321,11 @@ impl<'tcx> Ty<'tcx> {
22692321
self.0.0.flags
22702322
}
22712323

2324+
#[inline]
2325+
pub fn is_tuple(self) -> bool {
2326+
matches!(self.kind(), Tuple(..))
2327+
}
2328+
22722329
#[inline]
22732330
pub fn is_unit(self) -> bool {
22742331
match self.kind() {
@@ -2622,6 +2679,11 @@ impl<'tcx> Ty<'tcx> {
26222679
matches!(self.kind(), FnDef(..) | FnPtr(_))
26232680
}
26242681

2682+
#[inline]
2683+
pub fn is_fn_def(self) -> bool {
2684+
matches!(self.kind(), FnDef(..))
2685+
}
2686+
26252687
#[inline]
26262688
pub fn is_fn_ptr(self) -> bool {
26272689
matches!(self.kind(), FnPtr(_))

compiler/rustc_symbol_mangling/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@
9191
#![cfg_attr(not(bootstrap), doc(rust_logo))]
9292
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
9393
#![cfg_attr(not(bootstrap), allow(internal_features))]
94+
#![feature(iter_order_by)]
95+
#![feature(let_chains)]
9496
#![feature(never_type)]
9597
#![recursion_limit = "256"]
9698
#![allow(rustc::potential_query_instability)]

compiler/rustc_symbol_mangling/src/typeid.rs

+37-27
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::{FnSig, Instance, Ty, TyCtxt};
7+
use rustc_middle::ty::{Instance, List, Ty, TyCtxt};
88
use rustc_target::abi::call::FnAbi;
99
use std::hash::Hasher;
1010
use twox_hash::XxHash64;
@@ -26,16 +26,11 @@ pub fn typeid_for_fnabi<'tcx>(
2626
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
2727
options: TypeIdOptions,
2828
) -> String {
29-
typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options)
30-
}
31-
32-
/// Returns a type metadata identifier for the specified FnSig.
33-
pub fn typeid_for_fnsig<'tcx>(
34-
tcx: TyCtxt<'tcx>,
35-
fn_sig: &FnSig<'tcx>,
36-
options: TypeIdOptions,
37-
) -> String {
38-
typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options)
29+
typeid_itanium_cxx_abi::typeid_for_fnabi(
30+
tcx,
31+
&typeid_itanium_cxx_abi::transform_fnabi(tcx, &fn_abi, options, None),
32+
options,
33+
)
3934
}
4035

4136
/// Returns a type metadata identifier for the specified Instance.
@@ -44,7 +39,16 @@ pub fn typeid_for_instance<'tcx>(
4439
instance: &Instance<'tcx>,
4540
options: TypeIdOptions,
4641
) -> String {
47-
typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
42+
let fn_abi = tcx
43+
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, List::empty())))
44+
.unwrap_or_else(|instance| {
45+
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
46+
});
47+
typeid_itanium_cxx_abi::typeid_for_fnabi(
48+
tcx,
49+
&typeid_itanium_cxx_abi::transform_fnabi(tcx, &fn_abi, options, Some(instance)),
50+
options,
51+
)
4852
}
4953

5054
/// Returns a KCFI type metadata identifier for the specified FnAbi.
@@ -56,20 +60,14 @@ pub fn kcfi_typeid_for_fnabi<'tcx>(
5660
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
5761
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
5862
let mut hash: XxHash64 = Default::default();
59-
hash.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes());
60-
hash.finish() as u32
61-
}
62-
63-
/// Returns a KCFI type metadata identifier for the specified FnSig.
64-
pub fn kcfi_typeid_for_fnsig<'tcx>(
65-
tcx: TyCtxt<'tcx>,
66-
fn_sig: &FnSig<'tcx>,
67-
options: TypeIdOptions,
68-
) -> u32 {
69-
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
70-
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
71-
let mut hash: XxHash64 = Default::default();
72-
hash.write(typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options).as_bytes());
63+
hash.write(
64+
typeid_itanium_cxx_abi::typeid_for_fnabi(
65+
tcx,
66+
&typeid_itanium_cxx_abi::transform_fnabi(tcx, &fn_abi, options, None),
67+
options,
68+
)
69+
.as_bytes(),
70+
);
7371
hash.finish() as u32
7472
}
7573

@@ -79,9 +77,21 @@ pub fn kcfi_typeid_for_instance<'tcx>(
7977
instance: &Instance<'tcx>,
8078
options: TypeIdOptions,
8179
) -> u32 {
80+
let fn_abi = tcx
81+
.fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, List::empty())))
82+
.unwrap_or_else(|instance| {
83+
bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
84+
});
8285
// A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
8386
// xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
8487
let mut hash: XxHash64 = Default::default();
85-
hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
88+
hash.write(
89+
typeid_itanium_cxx_abi::typeid_for_fnabi(
90+
tcx,
91+
&typeid_itanium_cxx_abi::transform_fnabi(tcx, &fn_abi, options, Some(instance)),
92+
options,
93+
)
94+
.as_bytes(),
95+
);
8696
hash.finish() as u32
8797
}

0 commit comments

Comments
 (0)