Skip to content

Commit c097e48

Browse files
authoredAug 8, 2023
Rollup merge of #113593 - rcvalle:rust-cfi-fix-90546, r=wesleywiser
CFI: Fix error compiling core with LLVM CFI enabled Fix #90546 by filtering out global value function pointer types from the type tests, and adding the LowerTypeTests pass to the rustc LTO optimization pipelines.
2 parents 095619a + f837c48 commit c097e48

14 files changed

+90
-31
lines changed
 

‎compiler/rustc_codegen_llvm/src/back/write.rs

+3
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,8 @@ pub(crate) unsafe fn llvm_optimize(
472472
Some(llvm::SanitizerOptions {
473473
sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
474474
sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
475+
sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI),
476+
sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI),
475477
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
476478
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
477479
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
@@ -507,6 +509,7 @@ pub(crate) unsafe fn llvm_optimize(
507509
&*module.module_llvm.tm,
508510
to_pass_builder_opt_level(opt_level),
509511
opt_stage,
512+
cgcx.opts.cg.linker_plugin_lto.enabled(),
510513
config.no_prepopulate_passes,
511514
config.verify_llvm_ir,
512515
using_thin_buffers,

‎compiler/rustc_codegen_llvm/src/builder.rs

+22-21
Original file line numberDiff line numberDiff line change
@@ -1512,9 +1512,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
15121512
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
15131513
llfn: &'ll Value,
15141514
) {
1515-
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
1516-
if is_indirect_call && fn_abi.is_some() && self.tcx.sess.is_sanitizer_cfi_enabled() {
1517-
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::CFI) {
1515+
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
1516+
if self.tcx.sess.is_sanitizer_cfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
1517+
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::CFI) {
15181518
return;
15191519
}
15201520

@@ -1526,7 +1526,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
15261526
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
15271527
}
15281528

1529-
let typeid = typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
1529+
let typeid = typeid_for_fnabi(self.tcx, fn_abi, options);
15301530
let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
15311531

15321532
// Test whether the function pointer is associated with the type identifier.
@@ -1550,25 +1550,26 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
15501550
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
15511551
llfn: &'ll Value,
15521552
) -> Option<llvm::OperandBundleDef<'ll>> {
1553-
let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
1554-
let kcfi_bundle = if is_indirect_call && self.tcx.sess.is_sanitizer_kcfi_enabled() {
1555-
if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::KCFI) {
1556-
return None;
1557-
}
1553+
let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
1554+
let kcfi_bundle =
1555+
if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
1556+
if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::KCFI) {
1557+
return None;
1558+
}
15581559

1559-
let mut options = TypeIdOptions::empty();
1560-
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
1561-
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
1562-
}
1563-
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
1564-
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
1565-
}
1560+
let mut options = TypeIdOptions::empty();
1561+
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
1562+
options.insert(TypeIdOptions::GENERALIZE_POINTERS);
1563+
}
1564+
if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
1565+
options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
1566+
}
15661567

1567-
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
1568-
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
1569-
} else {
1570-
None
1571-
};
1568+
let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
1569+
Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
1570+
} else {
1571+
None
1572+
};
15721573
kcfi_bundle
15731574
}
15741575
}

‎compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+4
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ pub enum OptStage {
475475
pub struct SanitizerOptions {
476476
pub sanitize_address: bool,
477477
pub sanitize_address_recover: bool,
478+
pub sanitize_cfi: bool,
479+
pub sanitize_kcfi: bool,
478480
pub sanitize_memory: bool,
479481
pub sanitize_memory_recover: bool,
480482
pub sanitize_memory_track_origins: c_int,
@@ -894,6 +896,7 @@ extern "C" {
894896
pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
895897
pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata;
896898
pub fn LLVMIsAFunction(Val: &Value) -> Option<&Value>;
899+
pub fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool;
897900

898901
// Operations on constants of any type
899902
pub fn LLVMConstNull(Ty: &Type) -> &Value;
@@ -2138,6 +2141,7 @@ extern "C" {
21382141
TM: &'a TargetMachine,
21392142
OptLevel: PassBuilderOptLevel,
21402143
OptStage: OptStage,
2144+
IsLinkerPluginLTO: bool,
21412145
NoPrepopulatePasses: bool,
21422146
VerifyIR: bool,
21432147
UseThinLTOBuffers: bool,

‎compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/Transforms/IPO/AlwaysInliner.h"
3131
#include "llvm/Transforms/IPO/FunctionImport.h"
3232
#include "llvm/Transforms/IPO/Internalize.h"
33+
#include "llvm/Transforms/IPO/LowerTypeTests.h"
3334
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
3435
#include "llvm/Transforms/Utils/AddDiscriminators.h"
3536
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
@@ -609,6 +610,8 @@ enum class LLVMRustOptStage {
609610
struct LLVMRustSanitizerOptions {
610611
bool SanitizeAddress;
611612
bool SanitizeAddressRecover;
613+
bool SanitizeCFI;
614+
bool SanitizeKCFI;
612615
bool SanitizeMemory;
613616
bool SanitizeMemoryRecover;
614617
int SanitizeMemoryTrackOrigins;
@@ -625,6 +628,7 @@ LLVMRustOptimize(
625628
LLVMTargetMachineRef TMRef,
626629
LLVMRustPassBuilderOptLevel OptLevelRust,
627630
LLVMRustOptStage OptStage,
631+
bool IsLinkerPluginLTO,
628632
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
629633
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
630634
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
@@ -736,6 +740,18 @@ LLVMRustOptimize(
736740
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
737741
OptimizerLastEPCallbacks;
738742

743+
if (!IsLinkerPluginLTO
744+
&& SanitizerOptions && SanitizerOptions->SanitizeCFI
745+
&& !NoPrepopulatePasses) {
746+
PipelineStartEPCallbacks.push_back(
747+
[](ModulePassManager &MPM, OptimizationLevel Level) {
748+
MPM.addPass(LowerTypeTestsPass(/*ExportSummary=*/nullptr,
749+
/*ImportSummary=*/nullptr,
750+
/*DropTypeTests=*/false));
751+
}
752+
);
753+
}
754+
739755
if (VerifyIR) {
740756
PipelineStartEPCallbacks.push_back(
741757
[VerifyIR](ModulePassManager &MPM, OptimizationLevel Level) {

‎compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -2033,3 +2033,14 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) {
20332033
extern "C" bool LLVMRustIsBitcode(char *ptr, size_t len) {
20342034
return identify_magic(StringRef(ptr, len)) == file_magic::bitcode;
20352035
}
2036+
2037+
extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) {
2038+
if (unwrap<Value>(V)->getType()->isPointerTy()) {
2039+
if (auto *GV = dyn_cast<GlobalValue>(unwrap<Value>(V))) {
2040+
if (GV->getValueType()->isFunctionTy())
2041+
return false;
2042+
}
2043+
return true;
2044+
}
2045+
return false;
2046+
}

‎compiler/rustc_session/messages.ftl

+3-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-genera
8989
9090
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
9191
92-
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
92+
session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`
93+
94+
session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
9395
9496
session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
9597

‎compiler/rustc_session/src/errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ pub struct CannotEnableCrtStaticLinux;
114114
#[diag(session_sanitizer_cfi_requires_lto)]
115115
pub struct SanitizerCfiRequiresLto;
116116

117+
#[derive(Diagnostic)]
118+
#[diag(session_sanitizer_cfi_requires_single_codegen_unit)]
119+
pub struct SanitizerCfiRequiresSingleCodegenUnit;
120+
117121
#[derive(Diagnostic)]
118122
#[diag(session_sanitizer_cfi_canonical_jump_tables_requires_cfi)]
119123
pub struct SanitizerCfiCanonicalJumpTablesRequiresCfi;

‎compiler/rustc_session/src/session.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1619,13 +1619,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
16191619

16201620
// LLVM CFI requires LTO.
16211621
if sess.is_sanitizer_cfi_enabled()
1622-
&& !(sess.lto() == config::Lto::Fat
1623-
|| sess.lto() == config::Lto::Thin
1624-
|| sess.opts.cg.linker_plugin_lto.enabled())
1622+
&& !(sess.lto() == config::Lto::Fat || sess.opts.cg.linker_plugin_lto.enabled())
16251623
{
16261624
sess.emit_err(errors::SanitizerCfiRequiresLto);
16271625
}
16281626

1627+
// LLVM CFI using rustc LTO requires a single codegen unit.
1628+
if sess.is_sanitizer_cfi_enabled()
1629+
&& sess.lto() == config::Lto::Fat
1630+
&& !(sess.codegen_units().as_usize() == 1)
1631+
{
1632+
sess.emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
1633+
}
1634+
16291635
// LLVM CFI is incompatible with LLVM KCFI.
16301636
if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
16311637
sess.emit_err(errors::CannotMixAndMatchSanitizers {

‎tests/ui/lto/issue-100772.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// run-pass
1+
// build-pass
22
// needs-sanitizer-cfi
3-
// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
3+
// compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
44
// no-prefer-dynamic
55
// only-x86_64-unknown-linux-gnu
66

‎tests/ui/sanitize/issue-111184-generator-witness.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// encode_ty and caused the compiler to ICE.
33
//
44
// needs-sanitizer-cfi
5-
// compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi --edition=2021
5+
// compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi --edition=2021
66
// no-prefer-dynamic
77
// only-x86_64-unknown-linux-gnu
8-
// run-pass
8+
// build-pass
99

1010
use std::future::Future;
1111

‎tests/ui/sanitize/sanitizer-cfi-requires-lto.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Verifies that `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`.
1+
// Verifies that `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`.
22
//
33
// needs-sanitizer-cfi
44
// compile-flags: -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
1+
error: `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`
22

33
error: aborting due to previous error
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Verifies that `-Zsanitizer=cfi` with `-Clto` or `-Clto=thin` requires `-Ccodegen-units=1`.
2+
//
3+
// needs-sanitizer-cfi
4+
// compile-flags: -Ccodegen-units=2 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi
5+
6+
#![feature(no_core)]
7+
#![no_core]
8+
#![no_main]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
2+
3+
error: aborting due to previous error
4+

0 commit comments

Comments
 (0)
Please sign in to comment.