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
20 changes: 17 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;

use super::prelude::*;
Expand Down Expand Up @@ -592,7 +592,8 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
r#"memory = "on|off""#,
r#"memtag = "on|off""#,
r#"shadow_call_stack = "on|off""#,
r#"thread = "on|off""#
r#"thread = "on|off""#,
r#"realtime = "nonblocking|blocking|caller""#,
]);

const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
Expand All @@ -606,6 +607,7 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {

let mut on_set = SanitizerSet::empty();
let mut off_set = SanitizerSet::empty();
let mut rtsan = None;

for item in list.mixed() {
let Some(item) = item.meta_item() else {
Expand Down Expand Up @@ -654,6 +656,17 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK),
Some(sym::thread) => apply(SanitizerSet::THREAD),
Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS),
Some(sym::realtime) => match value.value_as_str() {
Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
_ => {
cx.expected_specific_argument_strings(
value.value_span,
&[sym::nonblocking, sym::blocking, sym::caller],
);
}
},
_ => {
cx.expected_specific_argument_strings(
item.path().span(),
Expand All @@ -666,13 +679,14 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
sym::shadow_call_stack,
sym::thread,
sym::hwaddress,
sym::realtime,
],
);
continue;
}
}
}

Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span })
Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
}
}
22 changes: 17 additions & 5 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Set and unset common attributes on LLVM values.
use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr, RtsanSetting};
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
Expand Down Expand Up @@ -98,10 +98,10 @@ fn patchable_function_entry_attrs<'ll>(
pub(crate) fn sanitize_attrs<'ll, 'tcx>(
cx: &SimpleCx<'ll>,
tcx: TyCtxt<'tcx>,
no_sanitize: SanitizerSet,
sanitizer_fn_attr: SanitizerFnAttrs,
) -> SmallVec<[&'ll Attribute; 4]> {
let mut attrs = SmallVec::new();
let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
let enabled = tcx.sess.opts.unstable_opts.sanitizer - 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 @@ -131,6 +131,18 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>(
if enabled.contains(SanitizerSet::SAFESTACK) {
attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx));
}
if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::REALTIME) {
match sanitizer_fn_attr.rtsan_setting {
RtsanSetting::Nonblocking => {
attrs.push(llvm::AttributeKind::SanitizeRealtimeNonblocking.create_attr(cx.llcx))
}
RtsanSetting::Blocking => {
attrs.push(llvm::AttributeKind::SanitizeRealtimeBlocking.create_attr(cx.llcx))
}
// caller is the default, so no llvm attribute
RtsanSetting::Caller => (),
}
}
attrs
}

Expand Down Expand Up @@ -417,7 +429,7 @@ 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.no_sanitize));
to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.sanitizers));

// For non-naked functions, set branch protection attributes on aarch64.
if let Some(BranchProtection { bti, pac_ret, gcs }) =
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ pub(crate) unsafe fn llvm_optimize(
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
sanitize_realtime: config.sanitizer.contains(SanitizerSet::REALTIME),
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::attrs::Linkage;
use rustc_middle::dep_graph;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrs, SanitizerFnAttrs};
use rustc_middle::mir::mono::Visibility;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
Expand Down Expand Up @@ -105,7 +105,7 @@ 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, SanitizerSet::empty());
let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerFnAttrs::default());
attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
}

Expand Down Expand Up @@ -191,10 +191,10 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
}

pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) {
if attrs.no_sanitize.contains(SanitizerSet::ADDRESS) {
if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS) {
unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) };
}
if attrs.no_sanitize.contains(SanitizerSet::HWADDRESS) {
if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS) {
unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) };
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1803,7 +1803,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
&& is_indirect_call
{
if let Some(fn_attrs) = fn_attrs
&& fn_attrs.no_sanitize.contains(SanitizerSet::CFI)
&& fn_attrs.sanitizers.disabled.contains(SanitizerSet::CFI)
{
return;
}
Expand Down Expand Up @@ -1861,7 +1861,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
&& is_indirect_call
{
if let Some(fn_attrs) = fn_attrs
&& fn_attrs.no_sanitize.contains(SanitizerSet::KCFI)
&& fn_attrs.sanitizers.disabled.contains(SanitizerSet::KCFI)
{
return None;
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ pub(crate) enum AttributeKind {
DeadOnUnwind = 43,
DeadOnReturn = 44,
CapturesReadOnly = 45,
SanitizeRealtimeNonblocking = 46,
SanitizeRealtimeBlocking = 47,
}

/// LLVMIntPredicate
Expand Down Expand Up @@ -481,6 +483,7 @@ pub(crate) struct SanitizerOptions {
pub sanitize_memory: bool,
pub sanitize_memory_recover: bool,
pub sanitize_memory_track_origins: c_int,
pub sanitize_realtime: bool,
pub sanitize_thread: bool,
pub sanitize_hwaddress: bool,
pub sanitize_hwaddress_recover: bool,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,9 @@ fn add_sanitizer_libraries(
if sanitizer.contains(SanitizerSet::SAFESTACK) {
link_sanitizer_runtime(sess, flavor, linker, "safestack");
}
if sanitizer.contains(SanitizerSet::REALTIME) {
link_sanitizer_runtime(sess, flavor, linker, "rtsan");
}
}

fn link_sanitizer_runtime(
Expand Down
66 changes: 48 additions & 18 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@ use std::str::FromStr;
use rustc_abi::{Align, ExternAbi};
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, UsedBy};
use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, RtsanSetting, UsedBy};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
};
use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_span::{Ident, Span, sym};
use rustc_target::spec::SanitizerSet;

use crate::errors;
use crate::target_features::{
Expand Down Expand Up @@ -350,8 +349,12 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
codegen_fn_attrs.alignment =
Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment);

// Compute the disabled sanitizers.
codegen_fn_attrs.no_sanitize |= tcx.disabled_sanitizers_for(did);
// Per sanitizer override if it's in the default state
let sanitizers = tcx.sanitizer_settings_for(did);
codegen_fn_attrs.sanitizers.disabled |= sanitizers.disabled;
if codegen_fn_attrs.sanitizers.rtsan_setting == RtsanSetting::default() {
codegen_fn_attrs.sanitizers.rtsan_setting = sanitizers.rtsan_setting;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ok here that explicit #[sanitize(realtime = "blocking")] will be equivalent to not specifying the sanitizer attribute at all? It will also be overridden.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not completely sure what you mean.
The behaviour for the new sanitizer should be the same as for the other sanitizers. For example if address sanitizer is set in the passed in codegen_fn_attrs it doesn't matter what the value in the tcx.sanitizer_settings_for is, because of binary or.

For rtsan i have done the same: If the setting is non-default in the passed in codegen_fn_attrs it doesn't matter what the setting from tcx.sanitizer_settings_for is.

}
// On trait methods, inherit the `#[align]` of the trait's method prototype.
codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did));

Expand Down Expand Up @@ -455,18 +458,40 @@ fn check_result(
}

// warn that inline has no effect when no_sanitize is present
if !codegen_fn_attrs.no_sanitize.is_empty()
if codegen_fn_attrs.sanitizers != SanitizerFnAttrs::default()
&& codegen_fn_attrs.inline.always()
&& let (Some(no_sanitize_span), Some(inline_span)) =
&& let (Some(sanitize_span), Some(inline_span)) =
(interesting_spans.sanitize, interesting_spans.inline)
{
let hir_id = tcx.local_def_id_to_hir_id(did);
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| {
lint.primary_message("setting `sanitize` off will have no effect after inlining");
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, sanitize_span, |lint| {
lint.primary_message("non-default `sanitize` will have no effect after inlining");
lint.span_note(inline_span, "inlining requested here");
})
}

// warn for nonblocking async fn.
// This doesn't behave as expected, because the executor can run blocking code without the sanitizer noticing.
if codegen_fn_attrs.sanitizers.rtsan_setting == RtsanSetting::Nonblocking
&& let Some(sanitize_span) = interesting_spans.sanitize
// async function
&& (tcx.asyncness(did).is_async() || (tcx.is_closure_like(did.into())
// async block
&& (tcx.coroutine_is_async(did.into())
// async closure
|| tcx.coroutine_is_async(tcx.coroutine_for_closure(did)))))
{
let hir_id = tcx.local_def_id_to_hir_id(did);
tcx.node_span_lint(
lint::builtin::RTSAN_NONBLOCKING_ASYNC,
hir_id,
sanitize_span,
|lint| {
lint.primary_message(r#"the async executor can run blocking code, without realtime sanitizer catching it"#);
}
);
}

// error when specifying link_name together with link_ordinal
if let Some(_) = codegen_fn_attrs.symbol_name
&& let Some(_) = codegen_fn_attrs.link_ordinal
Expand Down Expand Up @@ -576,30 +601,35 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs
}

fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
fn sanitizer_settings_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerFnAttrs {
// Backtrack to the crate root.
let mut disabled = match tcx.opt_local_parent(did) {
let mut settings = match tcx.opt_local_parent(did) {
// Check the parent (recursively).
Some(parent) => tcx.disabled_sanitizers_for(parent),
Some(parent) => tcx.sanitizer_settings_for(parent),
// We reached the crate root without seeing an attribute, so
// there is no sanitizers to exclude.
None => SanitizerSet::empty(),
None => SanitizerFnAttrs::default(),
};

// Check for a sanitize annotation directly on this def.
if let Some((on_set, off_set)) = find_attr!(tcx.get_all_attrs(did), AttributeKind::Sanitize {on_set, off_set, ..} => (on_set, off_set))
if let Some((on_set, off_set, rtsan)) = find_attr!(tcx.get_all_attrs(did), AttributeKind::Sanitize {on_set, off_set, rtsan, ..} => (on_set, off_set, rtsan))
{
// the on set is the set of sanitizers explicitly enabled.
// we mask those out since we want the set of disabled sanitizers here
disabled &= !*on_set;
settings.disabled &= !*on_set;
// the off set is the set of sanitizers explicitly disabled.
// we or those in here.
disabled |= *off_set;
settings.disabled |= *off_set;
// the on set and off set are distjoint since there's a third option: unset.
// a node may not set the sanitizer setting in which case it inherits from parents.
// the code above in this function does this backtracking

// if rtsan was specified here override the parent
if let Some(rtsan) = rtsan {
settings.rtsan_setting = *rtsan;
}
}
disabled
settings
}

/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
Expand Down Expand Up @@ -731,7 +761,7 @@ pub(crate) fn provide(providers: &mut Providers) {
codegen_fn_attrs,
should_inherit_track_caller,
inherited_align,
disabled_sanitizers_for,
sanitizer_settings_for,
..*providers
};
}
18 changes: 17 additions & 1 deletion compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,16 @@ pub struct DebugVisualizer {
pub path: Symbol,
}

#[derive(Clone, Copy, Debug, Decodable, Encodable, Eq, PartialEq)]
#[derive(HashStable_Generic, PrintAttribute)]
#[derive_const(Default)]
pub enum RtsanSetting {
Nonblocking,
Blocking,
#[default]
Caller,
}

/// Represents parsed *built-in* inert attributes.
///
/// ## Overview
Expand Down Expand Up @@ -683,7 +693,13 @@ pub enum AttributeKind {
///
/// the on set and off set are distjoint since there's a third option: unset.
/// a node may not set the sanitizer setting in which case it inherits from parents.
Sanitize { on_set: SanitizerSet, off_set: SanitizerSet, span: Span },
/// rtsan is unset if None
Sanitize {
on_set: SanitizerSet,
off_set: SanitizerSet,
rtsan: Option<RtsanSetting>,
span: Span,
},

/// Represents `#[should_panic]`
ShouldPanic { reason: Option<Symbol>, span: Span },
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
// tidy-alphabetical-start
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
#![feature(const_default)]
#![feature(const_trait_impl)]
#![feature(debug_closure_helpers)]
#![feature(derive_const)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]
#![feature(variant_count)]
Expand Down
Loading
Loading