Skip to content

Commit 4949cf2

Browse files
Auto merge of #142681 - 1c3t3a:sanitize-off-on, r=<try>
Remove the `#[no_sanitize]` attribute in favor of `#[sanitize(xyz = "on|off")]` This came up during the sanitizer stabilization (#123617). Instead of a `#[no_sanitize(xyz)]` attribute, we would like to have a `#[sanitize(xyz = "on|off")]` attribute, which is more powerful and allows to be extended in the future (instead of just focusing on turning sanitizers off). The implementation is done according to what was [discussed on Zulip](https://rust-lang.zulipchat.com/#narrow/channel/343119-project-exploit-mitigations/topic/Stabilize.20the.20.60no_sanitize.60.20attribute/with/495377292)). The new attribute also works on modules, traits and impl items and thus enables usage as the following: ```rust #[sanitize(address = "off")] mod foo { fn unsanitized(..) {} #[sanitize(address = "on")] fn sanitized(..) {} } trait MyTrait { #[sanitize(address = "off")] fn unsanitized_default(..) {} } #[sanitize(thread = "off")] impl MyTrait for () { ... } ``` r? `@rcvalle`
2 parents cccf075 + a466546 commit 4949cf2

Some content is hidden

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

42 files changed

+873
-343
lines changed

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati
165165
166166
codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
167167
168-
codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
169-
.note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
168+
codegen_ssa_invalid_sanitize = invalid argument for `sanitize`
169+
.note = expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
170170
171171
codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
172172

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 96 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_attr_data_structures::{
99
use rustc_hir::def::DefKind;
1010
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
1111
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
12-
use rustc_hir::{self as hir, LangItem, lang_items};
12+
use rustc_hir::{self as hir, Attribute, LangItem, lang_items};
1313
use rustc_middle::middle::codegen_fn_attrs::{
1414
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
1515
};
@@ -86,7 +86,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
8686
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
8787

8888
let mut link_ordinal_span = None;
89-
let mut no_sanitize_span = None;
89+
let mut sanitize_span = None;
9090

9191
for attr in attrs.iter() {
9292
// In some cases, attribute are only valid on functions, but it's the `check_attr`
@@ -254,39 +254,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
254254
}
255255
}
256256
}
257-
sym::no_sanitize => {
258-
no_sanitize_span = Some(attr.span());
259-
if let Some(list) = attr.meta_item_list() {
260-
for item in list.iter() {
261-
match item.name() {
262-
Some(sym::address) => {
263-
codegen_fn_attrs.no_sanitize |=
264-
SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
265-
}
266-
Some(sym::cfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI,
267-
Some(sym::kcfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI,
268-
Some(sym::memory) => {
269-
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY
270-
}
271-
Some(sym::memtag) => {
272-
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG
273-
}
274-
Some(sym::shadow_call_stack) => {
275-
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK
276-
}
277-
Some(sym::thread) => {
278-
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD
279-
}
280-
Some(sym::hwaddress) => {
281-
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
282-
}
283-
_ => {
284-
tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
285-
}
286-
}
287-
}
288-
}
289-
}
257+
sym::sanitize => sanitize_span = Some(attr.span()),
290258
sym::instruction_set => {
291259
codegen_fn_attrs.instruction_set =
292260
attr.meta_item_list().and_then(|l| match &l[..] {
@@ -387,6 +355,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
387355
codegen_fn_attrs.alignment =
388356
Ord::max(codegen_fn_attrs.alignment, tcx.sess.opts.unstable_opts.min_function_alignment);
389357

358+
// Compute the disabled sanitizers.
359+
codegen_fn_attrs.no_sanitize |= tcx.disabled_sanitizers_for(did);
390360
// On trait methods, inherit the `#[align]` of the trait's method prototype.
391361
codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did));
392362

@@ -453,11 +423,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
453423

454424
if !codegen_fn_attrs.no_sanitize.is_empty()
455425
&& codegen_fn_attrs.inline.always()
456-
&& let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span)
426+
&& let (Some(sanitize_span), Some(inline_span)) = (sanitize_span, inline_span)
457427
{
458428
let hir_id = tcx.local_def_id_to_hir_id(did);
459-
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| {
460-
lint.primary_message("`no_sanitize` will have no effect after inlining");
429+
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, sanitize_span, |lint| {
430+
lint.primary_message("setting `sanitize` off will have no effect after inlining");
461431
lint.span_note(inline_span, "inlining requested here");
462432
})
463433
}
@@ -553,6 +523,87 @@ fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
553523
}
554524
}
555525

526+
/// For an attr that has the `sanitize` attribute, read the list of
527+
/// disabled sanitizers.
528+
fn parse_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> SanitizerSet {
529+
let mut result = SanitizerSet::empty();
530+
if let Some(list) = attr.meta_item_list() {
531+
for item in list.iter() {
532+
let MetaItemInner::MetaItem(set) = item else {
533+
tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
534+
break;
535+
};
536+
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
537+
match segments.as_slice() {
538+
// Similar to clang, sanitize(address = ..) and
539+
// sanitize(kernel_address = ..) control both ASan and KASan
540+
// Source: https://reviews.llvm.org/D44981.
541+
[sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::off) => {
542+
result |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
543+
}
544+
[sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::on) => {
545+
result &= !SanitizerSet::ADDRESS;
546+
result &= !SanitizerSet::KERNELADDRESS;
547+
}
548+
[sym::cfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::CFI,
549+
[sym::cfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::CFI,
550+
[sym::kcfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::KCFI,
551+
[sym::kcfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::KCFI,
552+
[sym::memory] if set.value_str() == Some(sym::off) => {
553+
result |= SanitizerSet::MEMORY
554+
}
555+
[sym::memory] if set.value_str() == Some(sym::on) => {
556+
result &= !SanitizerSet::MEMORY
557+
}
558+
[sym::memtag] if set.value_str() == Some(sym::off) => {
559+
result |= SanitizerSet::MEMTAG
560+
}
561+
[sym::memtag] if set.value_str() == Some(sym::on) => {
562+
result &= !SanitizerSet::MEMTAG
563+
}
564+
[sym::shadow_call_stack] if set.value_str() == Some(sym::off) => {
565+
result |= SanitizerSet::SHADOWCALLSTACK
566+
}
567+
[sym::shadow_call_stack] if set.value_str() == Some(sym::on) => {
568+
result &= !SanitizerSet::SHADOWCALLSTACK
569+
}
570+
[sym::thread] if set.value_str() == Some(sym::off) => {
571+
result |= SanitizerSet::THREAD
572+
}
573+
[sym::thread] if set.value_str() == Some(sym::on) => {
574+
result &= !SanitizerSet::THREAD
575+
}
576+
[sym::hwaddress] if set.value_str() == Some(sym::off) => {
577+
result |= SanitizerSet::HWADDRESS
578+
}
579+
[sym::hwaddress] if set.value_str() == Some(sym::on) => {
580+
result &= !SanitizerSet::HWADDRESS
581+
}
582+
_ => {
583+
tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
584+
}
585+
}
586+
}
587+
}
588+
result
589+
}
590+
591+
fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
592+
// Check for a sanitize annotation directly on this def.
593+
if let Some(attr) = tcx.get_attr(did, sym::sanitize) {
594+
return parse_sanitize_attr(tcx, attr);
595+
}
596+
597+
// Otherwise backtrack.
598+
match tcx.opt_local_parent(did) {
599+
// Check the parent (recursively).
600+
Some(parent) => tcx.disabled_sanitizers_for(parent),
601+
// We reached the crate root without seeing an attribute, so
602+
// there is no sanitizers to exclude.
603+
None => SanitizerSet::empty(),
604+
}
605+
}
606+
556607
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
557608
/// applied to the method prototype.
558609
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
@@ -692,6 +743,11 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
692743
}
693744

694745
pub(crate) fn provide(providers: &mut Providers) {
695-
*providers =
696-
Providers { codegen_fn_attrs, should_inherit_track_caller, inherited_align, ..*providers };
746+
*providers = Providers {
747+
codegen_fn_attrs,
748+
should_inherit_track_caller,
749+
inherited_align,
750+
disabled_sanitizers_for,
751+
..*providers
752+
};
697753
}

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,9 +1101,9 @@ impl IntoDiagArg for ExpectedPointerMutability {
11011101
}
11021102

11031103
#[derive(Diagnostic)]
1104-
#[diag(codegen_ssa_invalid_no_sanitize)]
1104+
#[diag(codegen_ssa_invalid_sanitize)]
11051105
#[note]
1106-
pub(crate) struct InvalidNoSanitize {
1106+
pub(crate) struct InvalidSanitize {
11071107
#[primary_span]
11081108
pub span: Span,
11091109
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -540,9 +540,8 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
540540
ungated!(track_caller, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
541541
ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding, EncodeCrossCrate::No),
542542
gated!(
543-
no_sanitize, Normal,
544-
template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
545-
EncodeCrossCrate::No, experimental!(no_sanitize)
543+
sanitize, Normal, template!(List: r#"address = "on|off", cfi = "on|off""#), ErrorPreceding,
544+
EncodeCrossCrate::No, sanitize, experimental!(sanitize),
546545
),
547546
gated!(
548547
coverage, Normal, template!(OneOf: &[sym::off, sym::on]),

compiler/rustc_feature/src/removed.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ declare_features! (
190190
(removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656),
191191
/// Allows `#[no_debug]`.
192192
(removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667),
193+
// Allows the use of `no_sanitize` attribute.
194+
/// The feature was renamed to `sanitize` and the attribute to `#[sanitize(xyz = "on|off")]`
195+
(removed, no_sanitize, "CURRENT_RUSTC_VERSION", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 1234),
193196
/// Note: this feature was previously recorded in a separate
194197
/// `STABLE_REMOVED` list because it, uniquely, was once stable but was
195198
/// then removed. But there was no utility storing it separately, so now

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,6 @@ declare_features! (
591591
(unstable, new_range, "1.86.0", Some(123741)),
592592
/// Allows `#![no_core]`.
593593
(unstable, no_core, "1.3.0", Some(29639)),
594-
/// Allows the use of `no_sanitize` attribute.
595-
(unstable, no_sanitize, "1.42.0", Some(39699)),
596594
/// Allows using the `non_exhaustive_omitted_patterns` lint.
597595
(unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)),
598596
/// Allows `for<T>` binders in where-clauses
@@ -625,6 +623,8 @@ declare_features! (
625623
(unstable, return_type_notation, "1.70.0", Some(109417)),
626624
/// Allows `extern "rust-cold"`.
627625
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
626+
/// Allows the use of the `sanitize` attribute.
627+
(unstable, sanitize, "CURRENT_RUSTC_VERSION", Some(39699)),
628628
/// Allows the use of SIMD types in functions declared in `extern` blocks.
629629
(unstable, simd_ffi, "1.0.0", Some(27731)),
630630
/// Allows specialization of implementations (RFC 1210).

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2298,18 +2298,18 @@ declare_lint! {
22982298

22992299
declare_lint! {
23002300
/// The `inline_no_sanitize` lint detects incompatible use of
2301-
/// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize].
2301+
/// [`#[inline(always)]`][inline] and [`#[sanitize(xyz = "off")]`][sanitize].
23022302
///
23032303
/// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute
2304-
/// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html
2304+
/// [sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html
23052305
///
23062306
/// ### Example
23072307
///
23082308
/// ```rust
2309-
/// #![feature(no_sanitize)]
2309+
/// #![feature(sanitize)]
23102310
///
23112311
/// #[inline(always)]
2312-
/// #[no_sanitize(address)]
2312+
/// #[sanitize(address = "off")]
23132313
/// fn x() {}
23142314
///
23152315
/// fn main() {
@@ -2322,11 +2322,11 @@ declare_lint! {
23222322
/// ### Explanation
23232323
///
23242324
/// The use of the [`#[inline(always)]`][inline] attribute prevents the
2325-
/// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working.
2325+
/// the [`#[sanitize(xyz = "off")]`][sanitize] attribute from working.
23262326
/// Consider temporarily removing `inline` attribute.
23272327
pub INLINE_NO_SANITIZE,
23282328
Warn,
2329-
"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`",
2329+
r#"detects incompatible use of `#[inline(always)]` and `#[sanitize(... = "off")]`"#,
23302330
}
23312331

23322332
declare_lint! {

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ pub struct CodegenFnAttrs {
4040
/// The `#[link_section = "..."]` attribute, or what executable section this
4141
/// should be placed in.
4242
pub link_section: Option<Symbol>,
43-
/// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
44-
/// instrumentation should be disabled inside the annotated function.
43+
/// The `#[sanitize(xyz = "off")]` attribute. Indicates sanitizers for which
44+
/// instrumentation should be disabled inside the function.
4545
pub no_sanitize: SanitizerSet,
4646
/// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
4747
/// be generated against a specific instruction set. Only usable on architectures which allow

compiler/rustc_middle/src/query/erase.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ trivial! {
342342
rustc_span::Symbol,
343343
rustc_span::Ident,
344344
rustc_target::spec::PanicStrategy,
345+
rustc_target::spec::SanitizerSet,
345346
rustc_type_ir::Variance,
346347
u32,
347348
usize,

compiler/rustc_middle/src/query/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ use rustc_session::lint::LintExpectationId;
100100
use rustc_span::def_id::LOCAL_CRATE;
101101
use rustc_span::source_map::Spanned;
102102
use rustc_span::{DUMMY_SP, Span, Symbol};
103-
use rustc_target::spec::PanicStrategy;
103+
use rustc_target::spec::{PanicStrategy, SanitizerSet};
104104
use {rustc_abi as abi, rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir};
105105

106106
use crate::infer::canonical::{self, Canonical};
@@ -2669,6 +2669,16 @@ rustc_queries! {
26692669
desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
26702670
separate_provide_extern
26712671
}
2672+
2673+
/// Checks for the nearest `#[sanitize(xyz = "off")]` or
2674+
/// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the
2675+
/// crate root.
2676+
///
2677+
/// Returns the set of sanitizers that is explicitly disabled for this def.
2678+
query disabled_sanitizers_for(key: LocalDefId) -> SanitizerSet {
2679+
desc { |tcx| "checking what set of sanitizers are enabled on `{}`", tcx.def_path_str(key) }
2680+
feedable
2681+
}
26722682
}
26732683

26742684
rustc_with_all_queries! { define_callbacks! }

0 commit comments

Comments
 (0)