diff options
| author | Bastian Kersting <bkersting@google.com> | 2025-06-18 12:53:34 +0000 |
|---|---|---|
| committer | Bastian Kersting <bkersting@google.com> | 2025-08-18 08:30:00 +0000 |
| commit | 3ef065bf872ce62a18336dca0daf47b3e9f7da64 (patch) | |
| tree | b4dccd0b519642cac3b2f057995f5b378c8abc01 /compiler/rustc_codegen_ssa | |
| parent | 425a9c0a0e365c0b8c6cfd00c2ded83a73bed9a0 (diff) | |
| download | rust-3ef065bf872ce62a18336dca0daf47b3e9f7da64.tar.gz rust-3ef065bf872ce62a18336dca0daf47b3e9f7da64.zip | |
Implement the #[sanitize(..)] attribute
This change implements the #[sanitize(..)] attribute, which opts to
replace the currently unstable #[no_sanitize]. Essentially the new
attribute works similar as #[no_sanitize], just with more flexible
options regarding where it is applied. E.g. it is possible to turn
a certain sanitizer either on or off:
`#[sanitize(address = "on|off")]`
This attribute now also applies to more places, e.g. it is possible
to turn off a sanitizer for an entire module or impl block:
```rust
\#[sanitize(address = "off")]
mod foo {
fn unsanitized(..) {}
#[sanitize(address = "on")]
fn sanitized(..) {}
}
\#[sanitize(thread = "off")]
impl MyTrait for () {
...
}
```
This attribute is enabled behind the unstable `sanitize` feature.
Diffstat (limited to 'compiler/rustc_codegen_ssa')
| -rw-r--r-- | compiler/rustc_codegen_ssa/messages.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 102 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/errors.rs | 8 |
3 files changed, 111 insertions, 2 deletions
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index b6cfea88363..75cc60587b8 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -174,6 +174,9 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomo codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize` .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` +codegen_ssa_invalid_sanitize = invalid argument for `sanitize` + .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread` + codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64 diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index af70f0deb07..068559497dd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -162,6 +162,7 @@ fn parse_patchable_function_entry( struct InterestingAttributeDiagnosticSpans { link_ordinal: Option<Span>, no_sanitize: Option<Span>, + sanitize: Option<Span>, inline: Option<Span>, no_mangle: Option<Span>, } @@ -335,6 +336,7 @@ fn process_builtin_attrs( codegen_fn_attrs.no_sanitize |= parse_no_sanitize_attr(tcx, attr).unwrap_or_default(); } + sym::sanitize => interesting_spans.sanitize = Some(attr.span()), sym::instruction_set => { codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr) } @@ -358,6 +360,8 @@ 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); // 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)); @@ -463,6 +467,17 @@ fn check_result( lint.span_note(inline_span, "inlining requested here"); }) } + if !codegen_fn_attrs.no_sanitize.is_empty() + && codegen_fn_attrs.inline.always() + && 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, sanitize_span, |lint| { + lint.primary_message("setting `sanitize` off will have no effect after inlining"); + lint.span_note(inline_span, "inlining requested here"); + }) + } // error when specifying link_name together with link_ordinal if let Some(_) = codegen_fn_attrs.link_name @@ -585,6 +600,84 @@ fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { } } +/// For an attr that has the `sanitize` attribute, read the list of +/// disabled sanitizers. +fn parse_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> SanitizerSet { + let mut result = SanitizerSet::empty(); + if let Some(list) = attr.meta_item_list() { + for item in list.iter() { + let MetaItemInner::MetaItem(set) = item else { + tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() }); + break; + }; + let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); + match segments.as_slice() { + [sym::address] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS + } + [sym::address] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::ADDRESS; + result &= !SanitizerSet::KERNELADDRESS; + } + [sym::cfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::CFI, + [sym::cfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::CFI, + [sym::kcfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::KCFI, + [sym::kcfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::KCFI, + [sym::memory] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::MEMORY + } + [sym::memory] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::MEMORY + } + [sym::memtag] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::MEMTAG + } + [sym::memtag] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::MEMTAG + } + [sym::shadow_call_stack] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::SHADOWCALLSTACK + } + [sym::shadow_call_stack] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::SHADOWCALLSTACK + } + [sym::thread] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::THREAD + } + [sym::thread] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::THREAD + } + [sym::hwaddress] if set.value_str() == Some(sym::off) => { + result |= SanitizerSet::HWADDRESS + } + [sym::hwaddress] if set.value_str() == Some(sym::on) => { + result &= !SanitizerSet::HWADDRESS + } + _ => { + tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() }); + } + } + } + } + result +} + +fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet { + // Check for a sanitize annotation directly on this def. + if let Some(attr) = tcx.get_attr(did, sym::sanitize) { + return parse_sanitize_attr(tcx, attr); + } + + // Otherwise backtrack. + match tcx.opt_local_parent(did) { + // Check the parent (recursively). + Some(parent) => tcx.disabled_sanitizers_for(parent), + // We reached the crate root without seeing an attribute, so + // there is no sanitizers to exclude. + None => SanitizerSet::empty(), + } +} + /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { @@ -709,6 +802,11 @@ pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> { } pub(crate) fn provide(providers: &mut Providers) { - *providers = - Providers { codegen_fn_attrs, should_inherit_track_caller, inherited_align, ..*providers }; + *providers = Providers { + codegen_fn_attrs, + should_inherit_track_caller, + inherited_align, + disabled_sanitizers_for, + ..*providers + }; } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 7ac830bcda9..913e0025f2e 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1129,6 +1129,14 @@ pub(crate) struct InvalidNoSanitize { } #[derive(Diagnostic)] +#[diag(codegen_ssa_invalid_sanitize)] +#[note] +pub(crate) struct InvalidSanitize { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(codegen_ssa_target_feature_safe_trait)] pub(crate) struct TargetFeatureSafeTrait { #[primary_span] |
