Skip to content

Commit 63d0c9f

Browse files
Auto merge of #147935 - luca3s:add-rtsan, r=<try>
Add LLVM realtime sanitizer try-job: aarch64-apple try-job: x86_64-gnu-llvm-20-3 try-job: test-various
2 parents d85276b + 255329d commit 63d0c9f

File tree

44 files changed

+459
-85
lines changed

Some content is hidden

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

44 files changed

+459
-85
lines changed

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
1+
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
22
use rustc_session::parse::feature_err;
33

44
use super::prelude::*;
@@ -592,7 +592,8 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
592592
r#"memory = "on|off""#,
593593
r#"memtag = "on|off""#,
594594
r#"shadow_call_stack = "on|off""#,
595-
r#"thread = "on|off""#
595+
r#"thread = "on|off""#,
596+
r#"realtime = "nonblocking|blocking|caller""#,
596597
]);
597598

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

607608
let mut on_set = SanitizerSet::empty();
608609
let mut off_set = SanitizerSet::empty();
610+
let mut rtsan = None;
609611

610612
for item in list.mixed() {
611613
let Some(item) = item.meta_item() else {
@@ -654,6 +656,17 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
654656
Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK),
655657
Some(sym::thread) => apply(SanitizerSet::THREAD),
656658
Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS),
659+
Some(sym::realtime) => match value.value_as_str() {
660+
Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
661+
Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
662+
Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
663+
_ => {
664+
cx.expected_specific_argument_strings(
665+
value.value_span,
666+
&[sym::nonblocking, sym::blocking, sym::caller],
667+
);
668+
}
669+
},
657670
_ => {
658671
cx.expected_specific_argument_strings(
659672
item.path().span(),
@@ -666,13 +679,14 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
666679
sym::shadow_call_stack,
667680
sym::thread,
668681
sym::hwaddress,
682+
sym::realtime,
669683
],
670684
);
671685
continue;
672686
}
673687
}
674688
}
675689

676-
Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span })
690+
Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
677691
}
678692
}

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Set and unset common attributes on LLVM values.
2-
use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr};
2+
use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr, RtsanSetting};
33
use rustc_hir::def_id::DefId;
44
use rustc_middle::middle::codegen_fn_attrs::{
5-
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
5+
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
66
};
77
use rustc_middle::ty::{self, TyCtxt};
88
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
@@ -98,10 +98,10 @@ fn patchable_function_entry_attrs<'ll>(
9898
pub(crate) fn sanitize_attrs<'ll, 'tcx>(
9999
cx: &SimpleCx<'ll>,
100100
tcx: TyCtxt<'tcx>,
101-
no_sanitize: SanitizerSet,
101+
sanitizer_fn_attr: SanitizerFnAttrs,
102102
) -> SmallVec<[&'ll Attribute; 4]> {
103103
let mut attrs = SmallVec::new();
104-
let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
104+
let enabled = tcx.sess.opts.unstable_opts.sanitizer - sanitizer_fn_attr.disabled;
105105
if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
106106
attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
107107
}
@@ -131,6 +131,18 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>(
131131
if enabled.contains(SanitizerSet::SAFESTACK) {
132132
attrs.push(llvm::AttributeKind::SanitizeSafeStack.create_attr(cx.llcx));
133133
}
134+
if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::REALTIME) {
135+
match sanitizer_fn_attr.rtsan_setting {
136+
RtsanSetting::Nonblocking => {
137+
attrs.push(llvm::AttributeKind::SanitizeRealtimeNonblocking.create_attr(cx.llcx))
138+
}
139+
RtsanSetting::Blocking => {
140+
attrs.push(llvm::AttributeKind::SanitizeRealtimeBlocking.create_attr(cx.llcx))
141+
}
142+
// caller is the default, so no llvm attribute
143+
RtsanSetting::Caller => (),
144+
}
145+
}
134146
attrs
135147
}
136148

@@ -417,7 +429,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
417429
// not used.
418430
} else {
419431
// Do not set sanitizer attributes for naked functions.
420-
to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.no_sanitize));
432+
to_add.extend(sanitize_attrs(cx, tcx, codegen_fn_attrs.sanitizers));
421433

422434
// For non-naked functions, set branch protection attributes on aarch64.
423435
if let Some(BranchProtection { bti, pac_ret, gcs }) =

compiler/rustc_codegen_llvm/src/back/write.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,7 @@ pub(crate) unsafe fn llvm_optimize(
631631
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
632632
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
633633
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
634+
sanitize_realtime: config.sanitizer.contains(SanitizerSet::REALTIME),
634635
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
635636
sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
636637
sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),

compiler/rustc_codegen_llvm/src/base.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_codegen_ssa::traits::*;
2020
use rustc_data_structures::small_c_str::SmallCStr;
2121
use rustc_hir::attrs::Linkage;
2222
use rustc_middle::dep_graph;
23-
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
23+
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrs, SanitizerFnAttrs};
2424
use rustc_middle::mir::mono::Visibility;
2525
use rustc_middle::ty::TyCtxt;
2626
use rustc_session::config::DebugInfo;
@@ -105,7 +105,7 @@ pub(crate) fn compile_codegen_unit(
105105
if let Some(entry) =
106106
maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit)
107107
{
108-
let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerSet::empty());
108+
let attrs = attributes::sanitize_attrs(&cx, tcx, SanitizerFnAttrs::default());
109109
attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
110110
}
111111

@@ -191,10 +191,10 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
191191
}
192192

193193
pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) {
194-
if attrs.no_sanitize.contains(SanitizerSet::ADDRESS) {
194+
if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS) {
195195
unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) };
196196
}
197-
if attrs.no_sanitize.contains(SanitizerSet::HWADDRESS) {
197+
if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS) {
198198
unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) };
199199
}
200200
}

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
18031803
&& is_indirect_call
18041804
{
18051805
if let Some(fn_attrs) = fn_attrs
1806-
&& fn_attrs.no_sanitize.contains(SanitizerSet::CFI)
1806+
&& fn_attrs.sanitizers.disabled.contains(SanitizerSet::CFI)
18071807
{
18081808
return;
18091809
}
@@ -1861,7 +1861,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
18611861
&& is_indirect_call
18621862
{
18631863
if let Some(fn_attrs) = fn_attrs
1864-
&& fn_attrs.no_sanitize.contains(SanitizerSet::KCFI)
1864+
&& fn_attrs.sanitizers.disabled.contains(SanitizerSet::KCFI)
18651865
{
18661866
return None;
18671867
}

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ pub(crate) enum AttributeKind {
290290
DeadOnReturn = 44,
291291
CapturesReadOnly = 45,
292292
CapturesNone = 46,
293+
SanitizeRealtimeNonblocking = 47,
294+
SanitizeRealtimeBlocking = 48,
293295
}
294296

295297
/// LLVMIntPredicate
@@ -482,6 +484,7 @@ pub(crate) struct SanitizerOptions {
482484
pub sanitize_memory: bool,
483485
pub sanitize_memory_recover: bool,
484486
pub sanitize_memory_track_origins: c_int,
487+
pub sanitize_realtime: bool,
485488
pub sanitize_thread: bool,
486489
pub sanitize_hwaddress: bool,
487490
pub sanitize_hwaddress_recover: bool,

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,9 @@ fn add_sanitizer_libraries(
12511251
if sanitizer.contains(SanitizerSet::SAFESTACK) {
12521252
link_sanitizer_runtime(sess, flavor, linker, "safestack");
12531253
}
1254+
if sanitizer.contains(SanitizerSet::REALTIME) {
1255+
link_sanitizer_runtime(sess, flavor, linker, "rtsan");
1256+
}
12541257
}
12551258

12561259
fn link_sanitizer_runtime(

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,19 @@ use std::str::FromStr;
33
use rustc_abi::{Align, ExternAbi};
44
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
55
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
6-
use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, UsedBy};
6+
use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, RtsanSetting, UsedBy};
77
use rustc_hir::def::DefKind;
88
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
99
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
1010
use rustc_middle::middle::codegen_fn_attrs::{
11-
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
11+
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
1212
};
1313
use rustc_middle::query::Providers;
1414
use rustc_middle::span_bug;
1515
use rustc_middle::ty::{self as ty, TyCtxt};
1616
use rustc_session::lint;
1717
use rustc_session::parse::feature_err;
1818
use rustc_span::{Ident, Span, sym};
19-
use rustc_target::spec::SanitizerSet;
2019

2120
use crate::errors;
2221
use crate::target_features::{
@@ -350,8 +349,10 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
350349
codegen_fn_attrs.alignment =
351350
Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment);
352351

353-
// Compute the disabled sanitizers.
354-
codegen_fn_attrs.no_sanitize |= tcx.disabled_sanitizers_for(did);
352+
// Passed in sanitizer settings are always the default.
353+
assert!(codegen_fn_attrs.sanitizers == SanitizerFnAttrs::default());
354+
// Replace with #[sanitize] value
355+
codegen_fn_attrs.sanitizers = tcx.sanitizer_settings_for(did);
355356
// On trait methods, inherit the `#[align]` of the trait's method prototype.
356357
codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did));
357358

@@ -455,18 +456,40 @@ fn check_result(
455456
}
456457

457458
// warn that inline has no effect when no_sanitize is present
458-
if !codegen_fn_attrs.no_sanitize.is_empty()
459+
if codegen_fn_attrs.sanitizers != SanitizerFnAttrs::default()
459460
&& codegen_fn_attrs.inline.always()
460-
&& let (Some(no_sanitize_span), Some(inline_span)) =
461+
&& let (Some(sanitize_span), Some(inline_span)) =
461462
(interesting_spans.sanitize, interesting_spans.inline)
462463
{
463464
let hir_id = tcx.local_def_id_to_hir_id(did);
464-
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| {
465-
lint.primary_message("setting `sanitize` off will have no effect after inlining");
465+
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, sanitize_span, |lint| {
466+
lint.primary_message("non-default `sanitize` will have no effect after inlining");
466467
lint.span_note(inline_span, "inlining requested here");
467468
})
468469
}
469470

471+
// warn for nonblocking async fn.
472+
// This doesn't behave as expected, because the executor can run blocking code without the sanitizer noticing.
473+
if codegen_fn_attrs.sanitizers.rtsan_setting == RtsanSetting::Nonblocking
474+
&& let Some(sanitize_span) = interesting_spans.sanitize
475+
// async function
476+
&& (tcx.asyncness(did).is_async() || (tcx.is_closure_like(did.into())
477+
// async block
478+
&& (tcx.coroutine_is_async(did.into())
479+
// async closure
480+
|| tcx.coroutine_is_async(tcx.coroutine_for_closure(did)))))
481+
{
482+
let hir_id = tcx.local_def_id_to_hir_id(did);
483+
tcx.node_span_lint(
484+
lint::builtin::RTSAN_NONBLOCKING_ASYNC,
485+
hir_id,
486+
sanitize_span,
487+
|lint| {
488+
lint.primary_message(r#"the async executor can run blocking code, without realtime sanitizer catching it"#);
489+
}
490+
);
491+
}
492+
470493
// error when specifying link_name together with link_ordinal
471494
if let Some(_) = codegen_fn_attrs.symbol_name
472495
&& let Some(_) = codegen_fn_attrs.link_ordinal
@@ -576,30 +599,35 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
576599
codegen_fn_attrs
577600
}
578601

579-
fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
602+
fn sanitizer_settings_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerFnAttrs {
580603
// Backtrack to the crate root.
581-
let mut disabled = match tcx.opt_local_parent(did) {
604+
let mut settings = match tcx.opt_local_parent(did) {
582605
// Check the parent (recursively).
583-
Some(parent) => tcx.disabled_sanitizers_for(parent),
606+
Some(parent) => tcx.sanitizer_settings_for(parent),
584607
// We reached the crate root without seeing an attribute, so
585608
// there is no sanitizers to exclude.
586-
None => SanitizerSet::empty(),
609+
None => SanitizerFnAttrs::default(),
587610
};
588611

589612
// Check for a sanitize annotation directly on this def.
590-
if let Some((on_set, off_set)) = find_attr!(tcx.get_all_attrs(did), AttributeKind::Sanitize {on_set, off_set, ..} => (on_set, off_set))
613+
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))
591614
{
592615
// the on set is the set of sanitizers explicitly enabled.
593616
// we mask those out since we want the set of disabled sanitizers here
594-
disabled &= !*on_set;
617+
settings.disabled &= !*on_set;
595618
// the off set is the set of sanitizers explicitly disabled.
596619
// we or those in here.
597-
disabled |= *off_set;
620+
settings.disabled |= *off_set;
598621
// the on set and off set are distjoint since there's a third option: unset.
599622
// a node may not set the sanitizer setting in which case it inherits from parents.
600623
// the code above in this function does this backtracking
624+
625+
// if rtsan was specified here override the parent
626+
if let Some(rtsan) = rtsan {
627+
settings.rtsan_setting = *rtsan;
628+
}
601629
}
602-
disabled
630+
settings
603631
}
604632

605633
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
@@ -731,7 +759,7 @@ pub(crate) fn provide(providers: &mut Providers) {
731759
codegen_fn_attrs,
732760
should_inherit_track_caller,
733761
inherited_align,
734-
disabled_sanitizers_for,
762+
sanitizer_settings_for,
735763
..*providers
736764
};
737765
}

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,16 @@ pub struct DebugVisualizer {
382382
pub path: Symbol,
383383
}
384384

385+
#[derive(Clone, Copy, Debug, Decodable, Encodable, Eq, PartialEq)]
386+
#[derive(HashStable_Generic, PrintAttribute)]
387+
#[derive_const(Default)]
388+
pub enum RtsanSetting {
389+
Nonblocking,
390+
Blocking,
391+
#[default]
392+
Caller,
393+
}
394+
385395
/// Represents parsed *built-in* inert attributes.
386396
///
387397
/// ## Overview
@@ -683,7 +693,13 @@ pub enum AttributeKind {
683693
///
684694
/// the on set and off set are distjoint since there's a third option: unset.
685695
/// a node may not set the sanitizer setting in which case it inherits from parents.
686-
Sanitize { on_set: SanitizerSet, off_set: SanitizerSet, span: Span },
696+
/// rtsan is unset if None
697+
Sanitize {
698+
on_set: SanitizerSet,
699+
off_set: SanitizerSet,
700+
rtsan: Option<RtsanSetting>,
701+
span: Span,
702+
},
687703

688704
/// Represents `#[should_panic]`
689705
ShouldPanic { reason: Option<Symbol>, span: Span },

compiler/rustc_hir/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
// tidy-alphabetical-start
66
#![feature(associated_type_defaults)]
77
#![feature(closure_track_caller)]
8+
#![feature(const_default)]
9+
#![feature(const_trait_impl)]
810
#![feature(debug_closure_helpers)]
11+
#![feature(derive_const)]
912
#![feature(exhaustive_patterns)]
1013
#![feature(never_type)]
1114
#![feature(variant_count)]

0 commit comments

Comments
 (0)