Skip to content

Commit 004aa15

Browse files
committed
Add cross-language LLVM CFI support to the Rust compiler
This commit adds cross-language LLVM Control Flow Integrity (CFI) support to the Rust compiler by adding the `-Zsanitizer-cfi-normalize-integers` option to be used with Clang `-fsanitize-cfi-icall-normalize-integers` for normalizing integer types (see https://reviews.llvm.org/D139395). It provides forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same virtual address space). For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, see design document in the tracking issue #89653. Cross-language LLVM CFI can be enabled with -Zsanitizer=cfi and -Zsanitizer-cfi-normalize-integers, and requires proper (i.e., non-rustc) LTO (i.e., -Clinker-plugin-lto).
1 parent fec9adc commit 004aa15

File tree

70 files changed

+1384
-387
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1384
-387
lines changed

compiler/rustc_codegen_gcc/src/asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
501501
if options.contains(InlineAsmOptions::NORETURN) {
502502
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
503503
let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
504-
self.call(self.type_void(), None, builtin_unreachable, &[], None);
504+
self.call(self.type_void(), None, None, builtin_unreachable, &[], None);
505505
}
506506

507507
// Write results to outputs.

compiler/rustc_codegen_gcc/src/builder.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use rustc_codegen_ssa::traits::{
3535
};
3636
use rustc_data_structures::fx::FxHashSet;
3737
use rustc_middle::bug;
38+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
3839
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
3940
use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
4041
use rustc_span::Span;
@@ -455,12 +456,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
455456
}
456457

457458
#[cfg(feature="master")]
458-
fn invoke(&mut self, typ: Type<'gcc>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
459+
fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
459460
let try_block = self.current_func().new_block("try");
460461

461462
let current_block = self.block.clone();
462463
self.block = try_block;
463-
let call = self.call(typ, None, func, args, None); // TODO(antoyo): use funclet here?
464+
let call = self.call(typ, fn_attrs, None, func, args, None); // TODO(antoyo): use funclet here?
464465
self.block = current_block;
465466

466467
let return_value = self.current_func()
@@ -483,8 +484,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
483484
}
484485

485486
#[cfg(not(feature="master"))]
486-
fn invoke(&mut self, typ: Type<'gcc>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
487-
let call_site = self.call(typ, None, func, args, None);
487+
fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: &CodegenFnAttrs, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
488+
let call_site = self.call(typ, fn_attrs, None, func, args, None);
488489
let condition = self.context.new_rvalue_from_int(self.bool_type, 1);
489490
self.llbb().end_with_conditional(None, condition, then, catch);
490491
if let Some(_fn_abi) = fn_abi {
@@ -1351,6 +1352,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
13511352
fn call(
13521353
&mut self,
13531354
_typ: Type<'gcc>,
1355+
_fn_attrs: Option<&CodegenFnAttrs>,
13541356
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
13551357
func: RValue<'gcc>,
13561358
args: &[RValue<'gcc>],

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
113113
_ if simple.is_some() => {
114114
// FIXME(antoyo): remove this cast when the API supports function.
115115
let func = unsafe { std::mem::transmute(simple.expect("simple")) };
116-
self.call(self.type_void(), None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
116+
self.call(self.type_void(), None, None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
117117
},
118118
sym::likely => {
119119
self.expect(args[0].immediate(), true)
@@ -326,7 +326,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
326326
let masked = self.and(addr, mask);
327327
self.bitcast(masked, void_ptr_type)
328328
},
329-
329+
330330
_ if name_str.starts_with("simd_") => {
331331
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
332332
Ok(llval) => llval,
@@ -354,7 +354,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
354354
fn abort(&mut self) {
355355
let func = self.context.get_builtin_function("abort");
356356
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
357-
self.call(self.type_void(), None, func, &[], None);
357+
self.call(self.type_void(), None, None, func, &[], None);
358358
}
359359

360360
fn assume(&mut self, value: Self::Value) {
@@ -1135,7 +1135,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
11351135

11361136
fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
11371137
if bx.sess().panic_strategy() == PanicStrategy::Abort {
1138-
bx.call(bx.type_void(), None, try_func, &[data], None);
1138+
bx.call(bx.type_void(), None, None, try_func, &[data], None);
11391139
// Return 0 unconditionally from the intrinsic call;
11401140
// we can never unwind.
11411141
let ret_align = bx.tcx.data_layout.i32_align.abi;
@@ -1204,21 +1204,21 @@ fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>,
12041204
let zero = bx.cx.context.new_rvalue_zero(bx.int_type);
12051205
let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]);
12061206
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
1207-
bx.call(catch_ty, None, catch_func, &[data, ptr], None);
1207+
bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
12081208
bx.ret(bx.const_i32(1));
12091209

12101210
// NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not
12111211
// generate a try/catch.
12121212
// FIXME(antoyo): add a check in the libgccjit API to prevent this.
12131213
bx.switch_to_block(current_block);
1214-
bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
1214+
bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
12151215
});
12161216

12171217
let func = unsafe { std::mem::transmute(func) };
12181218

12191219
// Note that no invoke is used here because by definition this function
12201220
// can't panic (that's what it's catching).
1221-
let ret = bx.call(llty, None, func, &[try_func, data, catch_func], None);
1221+
let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None);
12221222
let i32_align = bx.tcx().data_layout.i32_align.abi;
12231223
bx.store(ret, dest, i32_align);
12241224
}

compiler/rustc_codegen_gcc/src/type_.rs

-12
Original file line numberDiff line numberDiff line change
@@ -280,16 +280,4 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
280280
}
281281

282282
impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
283-
fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) {
284-
// Unsupported.
285-
}
286-
287-
fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
288-
// Unsupported.
289-
self.context.new_rvalue_from_int(self.int_type, 0)
290-
}
291-
292-
fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) {
293-
// Unsupported.
294-
}
295283
}

compiler/rustc_codegen_llvm/src/asm.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,9 @@ pub(crate) fn inline_asm_call<'ll>(
442442
);
443443

444444
let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
445-
bx.invoke(fty, None, v, inputs, dest, catch, funclet)
445+
bx.invoke(fty, None, None, v, inputs, dest, catch, funclet)
446446
} else {
447-
bx.call(fty, None, v, inputs, None)
447+
bx.call(fty, None, None, v, inputs, None)
448448
};
449449

450450
// Store mark in a metadata node so we can map LLVM errors

compiler/rustc_codegen_llvm/src/builder.rs

+88-30
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ use rustc_codegen_ssa::traits::*;
1515
use rustc_codegen_ssa::MemFlags;
1616
use rustc_data_structures::small_c_str::SmallCStr;
1717
use rustc_hir::def_id::DefId;
18+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
1819
use rustc_middle::ty::layout::{
1920
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
2021
};
2122
use rustc_middle::ty::{self, Ty, TyCtxt};
2223
use rustc_span::Span;
23-
use rustc_symbol_mangling::typeid::kcfi_typeid_for_fnabi;
24+
use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
2425
use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
25-
use rustc_target::spec::{HasTargetSpec, Target};
26+
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
2627
use std::borrow::Cow;
2728
use std::ffi::CStr;
2829
use std::iter;
@@ -216,6 +217,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
216217
fn invoke(
217218
&mut self,
218219
llty: &'ll Type,
220+
fn_attrs: Option<&CodegenFnAttrs>,
219221
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
220222
llfn: &'ll Value,
221223
args: &[&'ll Value],
@@ -230,19 +232,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
230232
let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
231233
let mut bundles = vec![funclet_bundle];
232234

233-
// Set KCFI operand bundle
234-
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
235-
let kcfi_bundle =
236-
if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
237-
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
238-
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
239-
} else {
240-
None
241-
};
242-
if kcfi_bundle.is_some() {
243-
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
244-
bundles.push(kcfi_bundle);
245-
}
235+
// Emit CFI pointer type membership test
236+
self.cfi_type_test(fn_attrs, fn_abi, llfn);
237+
238+
// Emit KCFI operand bundle
239+
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
240+
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
241+
bundles.push(kcfi_bundle);
246242

247243
bundles.retain(|bundle| bundle.is_some());
248244
let invoke = unsafe {
@@ -1183,6 +1179,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
11831179
fn call(
11841180
&mut self,
11851181
llty: &'ll Type,
1182+
fn_attrs: Option<&CodegenFnAttrs>,
11861183
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
11871184
llfn: &'ll Value,
11881185
args: &[&'ll Value],
@@ -1195,19 +1192,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
11951192
let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
11961193
let mut bundles = vec![funclet_bundle];
11971194

1198-
// Set KCFI operand bundle
1199-
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
1200-
let kcfi_bundle =
1201-
if let Some(fn_abi) = fn_abi && self.tcx.sess.is_sanitizer_kcfi_enabled() && is_indirect_call {
1202-
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
1203-
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
1204-
} else {
1205-
None
1206-
};
1207-
if kcfi_bundle.is_some() {
1208-
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
1209-
bundles.push(kcfi_bundle);
1210-
}
1195+
// Emit CFI pointer type membership test
1196+
self.cfi_type_test(fn_attrs, fn_abi, llfn);
1197+
1198+
// Emit KCFI operand bundle
1199+
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
1200+
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
1201+
bundles.push(kcfi_bundle);
12111202

12121203
bundles.retain(|bundle| bundle.is_some());
12131204
let call = unsafe {
@@ -1456,7 +1447,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
14561447

14571448
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
14581449
let (ty, f) = self.cx.get_intrinsic(intrinsic);
1459-
self.call(ty, None, f, args, None)
1450+
self.call(ty, None, None, f, args, None)
14601451
}
14611452

14621453
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
@@ -1518,7 +1509,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
15181509
format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
15191510
};
15201511
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
1521-
self.call(self.type_func(&[src_ty], dest_ty), None, f, &[val], None)
1512+
self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None)
15221513
}
15231514

15241515
pub(crate) fn landing_pad(
@@ -1535,4 +1526,71 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
15351526
llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED)
15361527
}
15371528
}
1529+
1530+
// Emits CFI pointer type membership tests.
1531+
fn cfi_type_test(
1532+
&mut self,
1533+
fn_attrs: Option<&CodegenFnAttrs>,
1534+
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
1535+
llfn: &'ll Value,
1536+
) {
1537+
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
1538+
if is_indirect_call && fn_abi.is_some() && self.tcx.sess.is_sanitizer_cfi_enabled() {
1539+
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::CFI) {
1540+
return;
1541+
}
1542+
1543+
let mut options = TypeIdOptions::empty();
1544+
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
1545+
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
1546+
}
1547+
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
1548+
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
1549+
}
1550+
1551+
let typeid = typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
1552+
let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
1553+
1554+
// Test whether the function pointer is associated with the type identifier.
1555+
let cond = self.type_test(llfn, typeid_metadata);
1556+
let bb_pass = self.append_sibling_block("type_test.pass");
1557+
let bb_fail = self.append_sibling_block("type_test.fail");
1558+
self.cond_br(cond, bb_pass, bb_fail);
1559+
1560+
self.switch_to_block(bb_fail);
1561+
self.abort();
1562+
self.unreachable();
1563+
1564+
self.switch_to_block(bb_pass);
1565+
}
1566+
}
1567+
1568+
// Emits KCFI operand bundles.
1569+
fn kcfi_operand_bundle(
1570+
&mut self,
1571+
fn_attrs: Option<&CodegenFnAttrs>,
1572+
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
1573+
llfn: &'ll Value,
1574+
) -> Option<llvm::OperandBundleDef<'ll>> {
1575+
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
1576+
let kcfi_bundle = if is_indirect_call && self.tcx.sess.is_sanitizer_kcfi_enabled() {
1577+
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::KCFI) {
1578+
return None;
1579+
}
1580+
1581+
let mut options = TypeIdOptions::empty();
1582+
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
1583+
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
1584+
}
1585+
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
1586+
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
1587+
}
1588+
1589+
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
1590+
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
1591+
} else {
1592+
None
1593+
};
1594+
kcfi_bundle
1595+
}
15381596
}

compiler/rustc_codegen_llvm/src/context.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -228,18 +228,29 @@ pub unsafe fn create_module<'ll>(
228228
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
229229
}
230230

231-
if sess.is_sanitizer_cfi_enabled() {
232-
// FIXME(rcvalle): Add support for non canonical jump tables.
231+
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
232+
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
233233
let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
234-
// FIXME(rcvalle): Add it with Override behavior flag.
235234
llvm::LLVMRustAddModuleFlag(
236235
llmod,
237-
llvm::LLVMModFlagBehavior::Warning,
236+
llvm::LLVMModFlagBehavior::Override,
238237
canonical_jump_tables,
239238
1,
240239
);
241240
}
242241

242+
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
243+
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
244+
let enable_split_lto_unit = "EnableSplitLTOUnit\0".as_ptr().cast();
245+
llvm::LLVMRustAddModuleFlag(
246+
llmod,
247+
llvm::LLVMModFlagBehavior::Override,
248+
enable_split_lto_unit,
249+
1,
250+
);
251+
}
252+
253+
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
243254
if sess.is_sanitizer_kcfi_enabled() {
244255
let kcfi = "kcfi\0".as_ptr().cast();
245256
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);

compiler/rustc_codegen_llvm/src/declare.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::type_::Type;
2020
use crate::value::Value;
2121
use rustc_codegen_ssa::traits::TypeMembershipMethods;
2222
use rustc_middle::ty::Ty;
23-
use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi};
23+
use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
2424
use smallvec::SmallVec;
2525

2626
/// Declare a function.
@@ -132,12 +132,31 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
132132
fn_abi.apply_attrs_llfn(self, llfn);
133133

134134
if self.tcx.sess.is_sanitizer_cfi_enabled() {
135-
let typeid = typeid_for_fnabi(self.tcx, fn_abi);
135+
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
136136
self.set_type_metadata(llfn, typeid);
137+
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS);
138+
self.add_type_metadata(llfn, typeid);
139+
let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS);
140+
self.add_type_metadata(llfn, typeid);
141+
let typeid = typeid_for_fnabi(
142+
self.tcx,
143+
fn_abi,
144+
TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
145+
);
146+
self.add_type_metadata(llfn, typeid);
137147
}
138148

139149
if self.tcx.sess.is_sanitizer_kcfi_enabled() {
140-
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
150+
// LLVM KCFI does not support multiple !kcfi_type attachments
151+
let mut options = TypeIdOptions::empty();
152+
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
153+
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
154+
}
155+
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
156+
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
157+
}
158+
159+
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
141160
self.set_kcfi_type_metadata(llfn, kcfi_typeid);
142161
}
143162

0 commit comments

Comments
 (0)