Skip to content

Commit 30e054f

Browse files
committed
Auto merge of rust-lang#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 rust-lang#116404. cc `@compiler-errors` `@workingjubilee`
2 parents ba52720 + 8e6b4e9 commit 30e054f

File tree

5 files changed

+84
-27
lines changed

5 files changed

+84
-27
lines changed

compiler/rustc_codegen_llvm/src/declare.rs

+26-26
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ 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;
23+
use rustc_data_structures::fx::FxIndexSet;
2224
use rustc_middle::ty::{Instance, Ty};
2325
use rustc_symbol_mangling::typeid::{
2426
kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
@@ -141,33 +143,31 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
141143

142144
if self.tcx.sess.is_sanitizer_cfi_enabled() {
143145
if let Some(instance) = instance {
144-
let typeid = typeid_for_instance(self.tcx, instance, TypeIdOptions::empty());
145-
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);
146+
let mut typeids = FxIndexSet::default();
147+
for options in [
148+
TypeIdOptions::GENERALIZE_POINTERS,
149+
TypeIdOptions::NORMALIZE_INTEGERS,
150+
TypeIdOptions::NO_SELF_TYPE_ERASURE,
151+
]
152+
.into_iter()
153+
.powerset()
154+
.map(TypeIdOptions::from_iter)
155+
{
156+
let typeid = typeid_for_instance(self.tcx, instance, options);
157+
if typeids.insert(typeid.clone()) {
158+
self.add_type_metadata(llfn, typeid);
159+
}
160+
}
158161
} else {
159-
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
160-
self.set_type_metadata(llfn, typeid);
161-
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS);
162-
self.add_type_metadata(llfn, typeid);
163-
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS);
164-
self.add_type_metadata(llfn, typeid);
165-
let typeid = typeid_for_fnabi(
166-
self.tcx,
167-
fn_abi,
168-
TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
169-
);
170-
self.add_type_metadata(llfn, typeid);
162+
for options in
163+
[TypeIdOptions::GENERALIZE_POINTERS, TypeIdOptions::NORMALIZE_INTEGERS]
164+
.into_iter()
165+
.powerset()
166+
.map(TypeIdOptions::from_iter)
167+
{
168+
let typeid = typeid_for_fnabi(self.tcx, fn_abi, options);
169+
self.add_type_metadata(llfn, typeid);
170+
}
171171
}
172172
}
173173

compiler/rustc_symbol_mangling/src/typeid.rs

+11
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,20 @@ bitflags! {
1313
/// Options for typeid_for_fnabi.
1414
#[derive(Clone, Copy, Debug)]
1515
pub struct TypeIdOptions: u32 {
16+
/// Generalizes pointers for compatibility with Clang
17+
/// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI
18+
/// support.
1619
const GENERALIZE_POINTERS = 1;
20+
/// Generalizes repr(C) user-defined type for extern function types with the "C" calling
21+
/// convention (or extern types) for cross-language LLVM CFI and KCFI support.
1722
const GENERALIZE_REPR_C = 2;
23+
/// Normalizes integers for compatibility with Clang
24+
/// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM
25+
/// CFI and KCFI support.
1826
const NORMALIZE_INTEGERS = 4;
27+
/// Do not perform self type erasure for attaching a secondary type id to methods with their
28+
/// concrete self so they can be used as function pointers.
29+
const NO_SELF_TYPE_ERASURE = 8;
1930
}
2031
}
2132

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,8 @@ pub fn typeid_for_instance<'tcx>(
11441144
instance.args = strip_receiver_auto(tcx, instance.args);
11451145
}
11461146

1147-
if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
1147+
if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE)
1148+
&& let Some(impl_id) = tcx.impl_of_method(instance.def_id())
11481149
&& let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
11491150
{
11501151
let impl_method = tcx.associated_item(instance.def_id());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Verifies that a secondary type metadata identifier is assigned to methods with their concrete
2+
// self so they can be used as function pointers.
3+
//
4+
//@ needs-sanitizer-cfi
5+
//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
6+
7+
#![crate_type="lib"]
8+
9+
trait Trait1 {
10+
fn foo(&self);
11+
}
12+
13+
struct Type1;
14+
15+
impl Trait1 for Type1 {
16+
fn foo(&self) {}
17+
// CHECK: define{{.*}}3foo{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}}
18+
}
19+
20+
21+
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"}
22+
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Verifies that casting a method to a function pointer works.
2+
//
3+
// FIXME(#122848): Remove only-linux when fixed.
4+
//@ only-linux
5+
//@ needs-sanitizer-cfi
6+
//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
7+
//@ run-pass
8+
9+
trait Trait1 {
10+
fn foo(&self);
11+
}
12+
13+
struct Type1;
14+
15+
impl Trait1 for Type1 {
16+
fn foo(&self) {}
17+
}
18+
19+
fn main() {
20+
let type1 = Type1 {};
21+
let f = <Type1 as Trait1>::foo;
22+
f(&type1);
23+
}

0 commit comments

Comments
 (0)