Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
llfn,
&cx.tcx.codegen_instance_attrs(instance.def),
Some(instance),
cx.sanitizer_ignorelist.as_ref(),
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ fn create_wrapper_function(
ty,
);

llfn_attrs_from_instance(cx, tcx, llfn, attrs, None);
llfn_attrs_from_instance(cx, tcx, llfn, attrs, None, None);

let no_return = if no_return {
// -> ! DIFlagNoReturn
Expand Down
65 changes: 63 additions & 2 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>(
cx: &SimpleCx<'ll>,
tcx: TyCtxt<'tcx>,
sanitizer_fn_attr: SanitizerFnAttrs,
enabled: SanitizerSet,
) -> SmallVec<[&'ll Attribute; 4]> {
let mut attrs = SmallVec::new();
let enabled = tcx.sess.sanitizers() - sanitizer_fn_attr.disabled;
if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
}
Expand Down Expand Up @@ -409,6 +409,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
llfn: &'ll Value,
codegen_fn_attrs: &CodegenFnAttrs,
instance: Option<ty::Instance<'tcx>>,
sanitizer_ignorelist: Option<&crate::llvm::SanitizerIgnoreList>,
) {
let sess = tcx.sess;
let mut to_add = SmallVec::<[_; 16]>::new();
Expand Down Expand Up @@ -470,7 +471,67 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
// not used.
} else {
// Do not set sanitizer attributes for naked functions.
to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.sanitizers));
let mut enabled = tcx.sess.sanitizers() - codegen_fn_attrs.sanitizers.disabled;
if let Some(ignorelist) = sanitizer_ignorelist {
if let Some(instance) = instance {
let sym_name = tcx.symbol_name(instance).name;
let span = tcx.def_span(instance.def_id());
let source_map = tcx.sess.source_map();
let filename =
source_map.span_to_filename(span).prefer_local_unconditionally().to_string();

let mainfile = tcx
.sess
.local_crate_source_file()
.and_then(|path| path.local_path().map(|p| p.display().to_string()))
.unwrap_or_default();

let demangled = rustc_middle::ty::print::with_no_trimmed_paths!(
tcx.def_path_str(instance.def_id())
);
let is_ignored = |section: &std::ffi::CStr| -> bool {
ignorelist.contains_prefix(section, c"fun", sym_name)
|| ignorelist.contains_prefix(section, c"fun", &demangled)
|| ignorelist.contains_prefix(section, c"src", &filename)
|| (!mainfile.is_empty()
&& ignorelist.contains_prefix(section, c"mainfile", &mainfile))
};

let ignore_address = is_ignored(c"address");
let ignore_kernel_address = ignore_address || is_ignored(c"kernel-address");
let ignore_hwaddress = is_ignored(c"hwaddress");
let ignore_kernel_hwaddress = ignore_hwaddress || is_ignored(c"kernel-hwaddress");

if enabled.contains(SanitizerSet::ADDRESS) && ignore_address {
enabled.remove(SanitizerSet::ADDRESS);
}
if enabled.contains(SanitizerSet::KERNELADDRESS) && ignore_kernel_address {
enabled.remove(SanitizerSet::KERNELADDRESS);
}
if enabled.contains(SanitizerSet::MEMORY) && is_ignored(c"memory") {
enabled.remove(SanitizerSet::MEMORY);
}
if enabled.contains(SanitizerSet::THREAD) && is_ignored(c"thread") {
enabled.remove(SanitizerSet::THREAD);
}
if enabled.contains(SanitizerSet::HWADDRESS) && ignore_hwaddress {
enabled.remove(SanitizerSet::HWADDRESS);
}
if enabled.contains(SanitizerSet::KERNELHWADDRESS) && ignore_kernel_hwaddress {
enabled.remove(SanitizerSet::KERNELHWADDRESS);
}
if enabled.contains(SanitizerSet::SAFESTACK) && is_ignored(c"safestack") {
enabled.remove(SanitizerSet::SAFESTACK);
}
if is_ignored(c"cfi") {
to_add.push(llvm::CreateAttrString(cx.llcx, "no-sanitize-cfi"));
}
if is_ignored(c"kcfi") {
to_add.push(llvm::CreateAttrString(cx.llcx, "no-sanitize-kcfi"));
}
}
}
to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.sanitizers, enabled));

// For non-naked functions, set branch protection attributes on aarch64.
if let Some(BranchProtection { bti, pac_ret, gcs }) =
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ pub(crate) fn compile_codegen_unit(
if let Some(entry) =
maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit)
{
let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerFnAttrs::default());
let attrs = attributes::sanitize_attrs(
&cx,
tcx,
SanitizerFnAttrs::default(),
tcx.sess.sanitizers(),
);
attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
}

Expand Down
16 changes: 15 additions & 1 deletion compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1832,7 +1832,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {

// Emit KCFI operand bundle
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) {
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|bundle| bundle.as_ref()) {
bundles.push(kcfi_bundle);
}

Expand Down Expand Up @@ -1875,6 +1875,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
{
return;
}
if crate::llvm::HasStringAttribute(self.llfn(), "no-sanitize-cfi") {
return;
}

let mut options = cfi::TypeIdOptions::empty();
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
Expand All @@ -1884,6 +1887,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
options.insert(cfi::TypeIdOptions::NORMALIZE_INTEGERS);
}

if self.cx.is_sanitizer_type_ignored(c"cfi", fn_abi) {
return;
}

let typeid = if let Some(instance) = instance {
cfi::typeid_for_instance(self.tcx, instance, options)
} else {
Expand Down Expand Up @@ -1933,6 +1940,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
{
return None;
}
if crate::llvm::HasStringAttribute(self.llfn(), "no-sanitize-kcfi") {
return None;
}

let mut options = kcfi::TypeIdOptions::empty();
if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
Expand All @@ -1942,6 +1952,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS);
}

if self.cx.is_sanitizer_type_ignored(c"kcfi", fn_abi) {
return None;
}

let kcfi_typeid = if let Some(instance) = instance {
kcfi::typeid_for_instance(self.tcx, instance, options)
} else {
Expand Down
16 changes: 15 additions & 1 deletion compiler/rustc_codegen_llvm/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_hashes::Hash128;
use rustc_hir::def_id::DefId;
use rustc_middle::bug;
use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar};
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::cstore::DllImport;
use tracing::debug;

Expand Down Expand Up @@ -446,3 +446,17 @@ impl AsCCharPtr for [u8] {
self.as_ptr().cast()
}
}

pub(crate) fn type_name_for_ignore_list<'tcx>(
tcx: TyCtxt<'tcx>,
fn_abi: &rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>,
) -> String {
let inputs: Vec<_> = fn_abi.args.iter().map(|arg| arg.layout.ty).collect();
let output = fn_abi.ret.layout.ty;
let mut fn_sig_kind = ty::FnSigKind::default();
fn_sig_kind = fn_sig_kind.set_safety(rustc_hir::Safety::Safe);
fn_sig_kind = fn_sig_kind.set_c_variadic(fn_abi.c_variadic);
let fn_sig = tcx.mk_fn_sig(inputs, output, fn_sig_kind);
let fn_ptr = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
ty::print::with_no_trimmed_paths!(fn_ptr.to_string())
}
46 changes: 46 additions & 0 deletions compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,52 @@ impl<'ll> CodegenCx<'ll, '_> {

base::set_variable_sanitizer_attrs(g, attrs);

if let Some(ignorelist) = &self.sanitizer_ignorelist {
let instance = ty::Instance::mono(self.tcx, def_id);
let sym_name = self.tcx.symbol_name(instance).name;
let span = self.tcx.def_span(def_id);
let source_map = self.tcx.sess.source_map();
let filename =
source_map.span_to_filename(span).prefer_local_unconditionally().to_string();
let ty_name = rustc_middle::ty::print::with_no_trimmed_paths!(
self.tcx.type_of(def_id).skip_binder().to_string()
);
let mainfile = self
.tcx
.sess
.local_crate_source_file()
.and_then(|path| path.local_path().map(|p| p.display().to_string()))
.unwrap_or_default();

let is_ignored = |section: &std::ffi::CStr| -> bool {
ignorelist.contains_prefix(section, c"global", sym_name)
|| ignorelist.contains_prefix(section, c"src", &filename)
|| (!mainfile.is_empty()
&& ignorelist.contains_prefix(section, c"mainfile", &mainfile))
|| ignorelist.contains_prefix(section, c"type", &ty_name)
};

let sanitizers = self.tcx.sess.sanitizers();
let ignore_address = is_ignored(c"address");
let ignore_kernel_address = ignore_address || is_ignored(c"kernel-address");
let ignore_hwaddress = is_ignored(c"hwaddress");
let ignore_kernel_hwaddress = ignore_hwaddress || is_ignored(c"kernel-hwaddress");

if (sanitizers.contains(rustc_target::spec::SanitizerSet::ADDRESS) && ignore_address)
|| (sanitizers.contains(rustc_target::spec::SanitizerSet::KERNELADDRESS)
&& ignore_kernel_address)
{
unsafe { llvm::LLVMRustSetNoSanitizeAddress(g) };
}
if (sanitizers.contains(rustc_target::spec::SanitizerSet::HWADDRESS)
&& ignore_hwaddress)
|| (sanitizers.contains(rustc_target::spec::SanitizerSet::KERNELHWADDRESS)
&& ignore_kernel_hwaddress)
{
unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(g) };
}
}

if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) {
// `USED` and `USED_LINKER` can't be used together.
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
Expand Down
33 changes: 33 additions & 0 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ pub(crate) struct FullCx<'ll, 'tcx> {
/// Extra per-CGU codegen state needed when coverage instrumentation is enabled.
pub coverage_cx: Option<coverageinfo::CguCoverageContext<'ll, 'tcx>>,
pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
pub sanitizer_ignorelist: Option<crate::llvm::SanitizerIgnoreList>,

eh_personality: Cell<Option<&'ll Value>>,
pub rust_try_fn: Cell<Option<(&'ll Type, &'ll Value)>>,
Expand Down Expand Up @@ -650,6 +651,26 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
None
};

// FIXME: This parses the ignorelist files for each CGU, which adds a performance overhead.
// Clang parses it once per frontend invocation. LLVM's `SpecialCaseList::inSection`
// mutates an internal `LazyInit` cache and is not thread-safe. We either need to wrap
// the queries in a lock or wait for LLVM to expose a thread-safe way to query it.
let sanitizer_ignorelist = if !tcx.sess.opts.unstable_opts.sanitizer_ignorelist.is_empty() {
for path in &tcx.sess.opts.unstable_opts.sanitizer_ignorelist {
let _ = tcx.sess.source_map().load_file(std::path::Path::new(path));
}
match crate::llvm::SanitizerIgnoreList::new(
&tcx.sess.opts.unstable_opts.sanitizer_ignorelist,
) {
Ok(list) => Some(list),
Err(err) => {
tcx.dcx().fatal(format!("failed to parse sanitizer ignorelist: {}", err));
}
}
} else {
None
};

GenericCx(
FullCx {
tcx,
Expand All @@ -669,6 +690,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
scalar_lltypes: Default::default(),
coverage_cx,
dbg_cx,
sanitizer_ignorelist,
eh_personality: Cell::new(None),
rust_try_fn: Cell::new(None),
intrinsics: Default::default(),
Expand Down Expand Up @@ -766,6 +788,17 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
1 << 6,
);
}

pub(crate) fn is_sanitizer_type_ignored(
&self,
sanitizer: &std::ffi::CStr,
fn_abi: &rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>,
) -> bool {
self.sanitizer_ignorelist.as_ref().is_some_and(|ignorelist| {
let type_name = crate::common::type_name_for_ignore_list(self.tcx, fn_abi);
ignorelist.contains_prefix(sanitizer, c"type", &type_name)
})
}
}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn get_type_of_global(&self, val: &'ll Value) -> &'ll Type {
Expand Down
Loading
Loading