Skip to content
Merged
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
113 changes: 107 additions & 6 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, UsedBy};
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;

use super::prelude::*;
Expand Down Expand Up @@ -464,18 +464,119 @@ impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
was_forced: true,
};
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
]);

fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> + 'c {
parse_tf_attribute(cx, args)
}
}

const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
pub(crate) struct SanitizeParser;

impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
const PATH: &[Symbol] = &[sym::sanitize];

// FIXME: still checked in check_attrs.rs
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);

const TEMPLATE: AttributeTemplate = template!(List: &[
r#"address = "on|off""#,
r#"kernel_address = "on|off""#,
r#"cfi = "on|off""#,
r#"hwaddress = "on|off""#,
r#"kcfi = "on|off""#,
r#"memory = "on|off""#,
r#"memtag = "on|off""#,
r#"shadow_call_stack = "on|off""#,
r#"thread = "on|off""#
]);

const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(list) = args.list() else {
cx.expected_list(cx.attr_span);
return None;
};

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

for item in list.mixed() {
let Some(item) = item.meta_item() else {
cx.expected_name_value(item.span(), None);
continue;
};

let path = item.path().word_sym();
let Some(value) = item.args().name_value() else {
cx.expected_name_value(item.span(), path);
continue;
};

let mut apply = |s: SanitizerSet| {
let is_on = match value.value_as_str() {
Some(sym::on) => true,
Some(sym::off) => false,
Some(_) => {
cx.expected_specific_argument_strings(
value.value_span,
&[sym::on, sym::off],
);
return;
}
None => {
cx.expected_string_literal(value.value_span, Some(value.value_as_lit()));
return;
}
};

if is_on {
on_set |= s;
} else {
off_set |= s;
}
};

match path {
Some(sym::address) | Some(sym::kernel_address) => {
apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
}
Some(sym::cfi) => apply(SanitizerSet::CFI),
Some(sym::kcfi) => apply(SanitizerSet::KCFI),
Some(sym::memory) => apply(SanitizerSet::MEMORY),
Some(sym::memtag) => apply(SanitizerSet::MEMTAG),
Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK),
Some(sym::thread) => apply(SanitizerSet::THREAD),
Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS),
_ => {
cx.expected_specific_argument_strings(
item.path().span(),
&[
sym::address,
sym::cfi,
sym::kcfi,
sym::memory,
sym::memtag,
sym::shadow_call_stack,
sym::thread,
sym::hwaddress,
],
);
continue;
}
}
}

Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span })
}
}
4 changes: 3 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ use crate::attributes::allow_unstable::{
use crate::attributes::body::CoroutineParser;
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
NoMangleParser, OptimizeParser, SanitizeParser, TargetFeatureParser, TrackCallerParser,
UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
Expand Down Expand Up @@ -184,6 +185,7 @@ attribute_parsers!(
Single<RustcLayoutScalarValidRangeEnd>,
Single<RustcLayoutScalarValidRangeStart>,
Single<RustcObjectLifetimeDefaultParser>,
Single<SanitizeParser>,
Single<ShouldPanicParser>,
Single<SkipDuringMethodDispatchParser>,
Single<TransparencyParser>,
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_codegen_ssa/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,6 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati

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}`

codegen_ssa_invalid_sanitize = invalid argument for `sanitize`
.note = expected one of: `address`, `kernel_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
Expand Down
89 changes: 15 additions & 74 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ fn process_builtin_attrs(
codegen_fn_attrs.linkage = linkage;
}
}
AttributeKind::Sanitize { span, .. } => {
interesting_spans.sanitize = Some(*span);
}
_ => {}
}
}
Expand All @@ -310,7 +313,6 @@ fn process_builtin_attrs(
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
}
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::sanitize => interesting_spans.sanitize = Some(attr.span()),
sym::instruction_set => {
codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
}
Expand Down Expand Up @@ -560,79 +562,9 @@ 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. `current_attr` holds the information about
/// previously parsed attributes.
fn parse_sanitize_attr(
tcx: TyCtxt<'_>,
attr: &Attribute,
current_attr: SanitizerSet,
) -> SanitizerSet {
let mut result = current_attr;
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() {
// Similar to clang, sanitize(address = ..) and
// sanitize(kernel_address = ..) control both ASan and KASan
// Source: https://reviews.llvm.org/D44981.
[sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::off) => {
result |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
}
[sym::address] | [sym::kernel_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 {
// Backtrack to the crate root.
let disabled = match tcx.opt_local_parent(did) {
let mut disabled = 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
Expand All @@ -641,8 +573,17 @@ 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, disabled);
if let Some((on_set, off_set)) = find_attr!(tcx.get_all_attrs(did), AttributeKind::Sanitize {on_set, off_set, ..} => (on_set, off_set))
{
// 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;
// the off set is the set of sanitizers explicitly disabled.
// we or those in here.
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
}
disabled
}
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1120,14 +1120,6 @@ impl IntoDiagArg for ExpectedPointerMutability {
}
}

#[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 {
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
use rustc_span::def_id::DefId;
use rustc_span::hygiene::Transparency;
use rustc_span::{Ident, Span, Symbol};
pub use rustc_target::spec::SanitizerSet;
use thin_vec::ThinVec;

use crate::attrs::pretty_printing::PrintAttribute;
Expand Down Expand Up @@ -505,6 +506,12 @@ pub enum AttributeKind {
/// Represents `#[rustc_object_lifetime_default]`.
RustcObjectLifetimeDefault,

/// Represents `#[sanitize]`
///
/// 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 },

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

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ impl AttributeKind {
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcObjectLifetimeDefault => No,
Sanitize { .. } => No,
ShouldPanic { .. } => No,
SkipDuringMethodDispatch { .. } => No,
SpecializationTrait(..) => No,
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_hir/src/attrs/pretty_printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rustc_ast::{AttrStyle, IntTy, UintTy};
use rustc_ast_pretty::pp::Printer;
use rustc_span::hygiene::Transparency;
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
use rustc_target::spec::SanitizerSet;
use thin_vec::ThinVec;

/// This trait is used to print attributes in `rustc_hir_pretty`.
Expand Down Expand Up @@ -146,4 +147,14 @@ macro_rules! print_tup {
print_tup!(A B C D E F G H);
print_skip!(Span, (), ErrorGuaranteed);
print_disp!(u16, bool, NonZero<u32>);
print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
print_debug!(
Symbol,
Ident,
UintTy,
IntTy,
Align,
AttrStyle,
CommentKind,
Transparency,
SanitizerSet,
);
Loading
Loading