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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1128,6 +1128,14 @@ pub(crate) struct InvalidNoSanitize {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
|
||||
@@ -745,6 +745,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
template!(List: &["address, kcfi, memory, thread"]), DuplicatesOk,
|
||||
EncodeCrossCrate::No, experimental!(no_sanitize)
|
||||
),
|
||||
gated!(
|
||||
sanitize, Normal, 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""#]), ErrorPreceding,
|
||||
EncodeCrossCrate::No, sanitize, experimental!(sanitize),
|
||||
),
|
||||
gated!(
|
||||
coverage, Normal, template!(OneOf: &[sym::off, sym::on]),
|
||||
ErrorPreceding, EncodeCrossCrate::No,
|
||||
|
||||
@@ -626,6 +626,8 @@ declare_features! (
|
||||
(unstable, return_type_notation, "1.70.0", Some(109417)),
|
||||
/// Allows `extern "rust-cold"`.
|
||||
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
|
||||
/// Allows the use of the `sanitize` attribute.
|
||||
(unstable, sanitize, "CURRENT_RUSTC_VERSION", Some(39699)),
|
||||
/// Allows the use of SIMD types in functions declared in `extern` blocks.
|
||||
(unstable, simd_ffi, "1.0.0", Some(27731)),
|
||||
/// Allows specialization of implementations (RFC 1210).
|
||||
|
||||
@@ -343,6 +343,7 @@ trivial! {
|
||||
rustc_span::Symbol,
|
||||
rustc_span::Ident,
|
||||
rustc_target::spec::PanicStrategy,
|
||||
rustc_target::spec::SanitizerSet,
|
||||
rustc_type_ir::Variance,
|
||||
u32,
|
||||
usize,
|
||||
|
||||
@@ -100,7 +100,7 @@ use rustc_session::lint::LintExpectationId;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use rustc_target::spec::{PanicStrategy, SanitizerSet};
|
||||
use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::infer::canonical::{self, Canonical};
|
||||
@@ -2686,6 +2686,16 @@ rustc_queries! {
|
||||
desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// Checks for the nearest `#[sanitize(xyz = "off")]` or
|
||||
/// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the
|
||||
/// crate root.
|
||||
///
|
||||
/// Returns the set of sanitizers that is explicitly disabled for this def.
|
||||
query disabled_sanitizers_for(key: LocalDefId) -> SanitizerSet {
|
||||
desc { |tcx| "checking what set of sanitizers are enabled on `{}`", tcx.def_path_str(key) }
|
||||
feedable
|
||||
}
|
||||
}
|
||||
|
||||
rustc_with_all_queries! { define_callbacks! }
|
||||
|
||||
@@ -542,6 +542,12 @@ passes_rustc_pub_transparent =
|
||||
attribute should be applied to `#[repr(transparent)]` types
|
||||
.label = not a `#[repr(transparent)]` type
|
||||
|
||||
passes_sanitize_attribute_not_allowed =
|
||||
sanitize attribute not allowed here
|
||||
.not_fn_impl_mod = not a function, impl block, or module
|
||||
.no_body = function has no body
|
||||
.help = sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
passes_should_be_applied_to_fn =
|
||||
attribute should be applied to a function definition
|
||||
.label = {$on_crate ->
|
||||
|
||||
@@ -261,6 +261,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
[sym::no_sanitize, ..] => {
|
||||
self.check_no_sanitize(attr, span, target)
|
||||
}
|
||||
[sym::sanitize, ..] => {
|
||||
self.check_sanitize(attr, span, target)
|
||||
}
|
||||
[sym::thread_local, ..] => self.check_thread_local(attr, span, target),
|
||||
[sym::doc, ..] => self.check_doc_attrs(
|
||||
attr,
|
||||
@@ -518,6 +521,46 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the `#[sanitize(..)]` attribute is applied to a
|
||||
/// function/closure/method, or to an impl block or module.
|
||||
fn check_sanitize(&self, attr: &Attribute, target_span: Span, target: Target) {
|
||||
let mut not_fn_impl_mod = None;
|
||||
let mut no_body = None;
|
||||
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for item in list.iter() {
|
||||
let MetaItemInner::MetaItem(set) = item else {
|
||||
return;
|
||||
};
|
||||
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match target {
|
||||
Target::Fn
|
||||
| Target::Closure
|
||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
|
||||
| Target::Impl { .. }
|
||||
| Target::Mod => return,
|
||||
Target::Static if matches!(segments.as_slice(), [sym::address]) => return,
|
||||
|
||||
// These are "functions", but they aren't allowed because they don't
|
||||
// have a body, so the usual explanation would be confusing.
|
||||
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
|
||||
no_body = Some(target_span);
|
||||
}
|
||||
|
||||
_ => {
|
||||
not_fn_impl_mod = Some(target_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.dcx().emit_err(errors::SanitizeAttributeNotAllowed {
|
||||
attr_span: attr.span(),
|
||||
not_fn_impl_mod,
|
||||
no_body,
|
||||
help: (),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `#[naked]` is applied to a function definition.
|
||||
fn check_naked(&self, hir_id: HirId, target: Target) {
|
||||
match target {
|
||||
@@ -561,7 +604,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `#[collapse_debuginfo]` is applied to a macro.
|
||||
fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) {
|
||||
match target {
|
||||
|
||||
@@ -1499,6 +1499,23 @@ pub(crate) struct NoSanitize<'a> {
|
||||
pub attr_str: &'a str,
|
||||
}
|
||||
|
||||
/// "sanitize attribute not allowed here"
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_sanitize_attribute_not_allowed)]
|
||||
pub(crate) struct SanitizeAttributeNotAllowed {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
/// "not a function, impl block, or module"
|
||||
#[label(passes_not_fn_impl_mod)]
|
||||
pub not_fn_impl_mod: Option<Span>,
|
||||
/// "function has no body"
|
||||
#[label(passes_no_body)]
|
||||
pub no_body: Option<Span>,
|
||||
/// "sanitize attribute can be applied to a function (with body), impl block, or module"
|
||||
#[help]
|
||||
pub help: (),
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): move back to rustc_attr
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_rustc_const_stable_indirect_pairing)]
|
||||
|
||||
118
tests/codegen-llvm/sanitizer/sanitize-off.rs
Normal file
118
tests/codegen-llvm/sanitizer/sanitize-off.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
// Verifies that the `#[sanitize(address = "off")]` attribute can be used to
|
||||
// selectively disable sanitizer instrumentation.
|
||||
//
|
||||
//@ needs-sanitizer-address
|
||||
//@ compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(sanitize)]
|
||||
|
||||
// CHECK: @UNSANITIZED = constant{{.*}} no_sanitize_address
|
||||
// CHECK-NOT: @__asan_global_SANITIZED
|
||||
#[no_mangle]
|
||||
#[sanitize(address = "off")]
|
||||
pub static UNSANITIZED: u32 = 0;
|
||||
|
||||
// CHECK: @__asan_global_SANITIZED
|
||||
#[no_mangle]
|
||||
pub static SANITIZED: u32 = 0;
|
||||
|
||||
// CHECK-LABEL: ; sanitize_off::unsanitized
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK-NOT: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
#[sanitize(address = "off")]
|
||||
pub fn unsanitized(b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
|
||||
// CHECK-LABEL: ; sanitize_off::sanitized
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
pub fn sanitized(b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
|
||||
#[sanitize(address = "off")]
|
||||
pub mod foo {
|
||||
// CHECK-LABEL: ; sanitize_off::foo::unsanitized
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK-NOT: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
pub fn unsanitized(b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
|
||||
// CHECK-LABEL: ; sanitize_off::foo::sanitized
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
#[sanitize(address = "on")]
|
||||
pub fn sanitized(b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MyTrait {
|
||||
fn unsanitized(&self, b: &mut u8) -> u8;
|
||||
fn sanitized(&self, b: &mut u8) -> u8;
|
||||
|
||||
// CHECK-LABEL: ; sanitize_off::MyTrait::unsanitized_default
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK-NOT: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
#[sanitize(address = "off")]
|
||||
fn unsanitized_default(&self, b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
|
||||
// CHECK-LABEL: ; sanitize_off::MyTrait::sanitized_default
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
fn sanitized_default(&self, b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
}
|
||||
|
||||
#[sanitize(address = "off")]
|
||||
impl MyTrait for () {
|
||||
// CHECK-LABEL: ; <() as sanitize_off::MyTrait>::unsanitized
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK-NOT: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK-NOT: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
fn unsanitized(&self, b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
|
||||
// CHECK-LABEL: ; <() as sanitize_off::MyTrait>::sanitized
|
||||
// CHECK-NEXT: ; Function Attrs:
|
||||
// CHECK: sanitize_address
|
||||
// CHECK: start:
|
||||
// CHECK: call void @__asan_report_load
|
||||
// CHECK: }
|
||||
#[sanitize(address = "on")]
|
||||
fn sanitized(&self, b: &mut u8) -> u8 {
|
||||
*b
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expose_trait(b: &mut u8) -> u8 {
|
||||
<() as MyTrait>::unsanitized_default(&(), b);
|
||||
<() as MyTrait>::sanitized_default(&(), b)
|
||||
}
|
||||
4
tests/ui/feature-gates/feature-gate-sanitize.rs
Normal file
4
tests/ui/feature-gates/feature-gate-sanitize.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[sanitize(address = "on")]
|
||||
//~^ ERROR the `#[sanitize]` attribute is an experimental feature
|
||||
fn main() {
|
||||
}
|
||||
13
tests/ui/feature-gates/feature-gate-sanitize.stderr
Normal file
13
tests/ui/feature-gates/feature-gate-sanitize.stderr
Normal file
@@ -0,0 +1,13 @@
|
||||
error[E0658]: the `#[sanitize]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-sanitize.rs:1:1
|
||||
|
|
||||
LL | #[sanitize(address = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #39699 <https://github.com/rust-lang/rust/issues/39699> for more information
|
||||
= help: add `#![feature(sanitize)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
22
tests/ui/sanitize-attr/invalid-sanitize.rs
Normal file
22
tests/ui/sanitize-attr/invalid-sanitize.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
#![feature(sanitize)]
|
||||
|
||||
#[sanitize(brontosaurus = "off")] //~ ERROR invalid argument
|
||||
fn main() {
|
||||
}
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR multiple `sanitize` attributes
|
||||
#[sanitize(address = "off")]
|
||||
fn multiple_consistent() {}
|
||||
|
||||
#[sanitize(address = "on")] //~ ERROR multiple `sanitize` attributes
|
||||
#[sanitize(address = "off")]
|
||||
fn multiple_inconsistent() {}
|
||||
|
||||
#[sanitize(address = "bogus")] //~ ERROR invalid argument for `sanitize`
|
||||
fn wrong_value() {}
|
||||
|
||||
#[sanitize = "off"] //~ ERROR malformed `sanitize` attribute input
|
||||
fn name_value () {}
|
||||
|
||||
#[sanitize] //~ ERROR malformed `sanitize` attribute input
|
||||
fn just_word() {}
|
||||
82
tests/ui/sanitize-attr/invalid-sanitize.stderr
Normal file
82
tests/ui/sanitize-attr/invalid-sanitize.stderr
Normal file
@@ -0,0 +1,82 @@
|
||||
error: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:18:1
|
||||
|
|
||||
LL | #[sanitize = "off"]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
|
|
||||
LL - #[sanitize = "off"]
|
||||
LL + #[sanitize(address = "on|off")]
|
||||
|
|
||||
LL - #[sanitize = "off"]
|
||||
LL + #[sanitize(cfi = "on|off")]
|
||||
|
|
||||
LL - #[sanitize = "off"]
|
||||
LL + #[sanitize(hwaddress = "on|off")]
|
||||
|
|
||||
LL - #[sanitize = "off"]
|
||||
LL + #[sanitize(kcfi = "on|off")]
|
||||
|
|
||||
= and 5 other candidates
|
||||
|
||||
error: malformed `sanitize` attribute input
|
||||
--> $DIR/invalid-sanitize.rs:21:1
|
||||
|
|
||||
LL | #[sanitize]
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: the following are the possible correct uses
|
||||
|
|
||||
LL | #[sanitize(address = "on|off")]
|
||||
| ++++++++++++++++++++
|
||||
LL | #[sanitize(cfi = "on|off")]
|
||||
| ++++++++++++++++
|
||||
LL | #[sanitize(hwaddress = "on|off")]
|
||||
| ++++++++++++++++++++++
|
||||
LL | #[sanitize(kcfi = "on|off")]
|
||||
| +++++++++++++++++
|
||||
= and 5 other candidates
|
||||
|
||||
error: multiple `sanitize` attributes
|
||||
--> $DIR/invalid-sanitize.rs:7:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/invalid-sanitize.rs:8:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: multiple `sanitize` attributes
|
||||
--> $DIR/invalid-sanitize.rs:11:1
|
||||
|
|
||||
LL | #[sanitize(address = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/invalid-sanitize.rs:12:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid argument for `sanitize`
|
||||
--> $DIR/invalid-sanitize.rs:3:1
|
||||
|
|
||||
LL | #[sanitize(brontosaurus = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
|
||||
|
||||
error: invalid argument for `sanitize`
|
||||
--> $DIR/invalid-sanitize.rs:15:1
|
||||
|
|
||||
LL | #[sanitize(address = "bogus")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
115
tests/ui/sanitize-attr/valid-sanitize.rs
Normal file
115
tests/ui/sanitize-attr/valid-sanitize.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
//! Tests where the `#[sanitize(..)]` attribute can and cannot be used.
|
||||
|
||||
#![feature(sanitize)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![warn(unused_attributes)]
|
||||
#![sanitize(address = "off", thread = "on")]
|
||||
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
mod submod {}
|
||||
|
||||
#[sanitize(address = "off")]
|
||||
static FOO: u32 = 0;
|
||||
|
||||
#[sanitize(thread = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
static BAR: u32 = 0;
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
type MyTypeAlias = ();
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
trait MyTrait {
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
const TRAIT_ASSOC_CONST: u32;
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
type TraitAssocType;
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
fn trait_method(&self);
|
||||
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
fn trait_method_with_default(&self) {}
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
fn trait_assoc_fn();
|
||||
}
|
||||
|
||||
#[sanitize(address = "off")]
|
||||
impl MyTrait for () {
|
||||
const TRAIT_ASSOC_CONST: u32 = 0;
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
type TraitAssocType = Self;
|
||||
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
fn trait_method(&self) {}
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
fn trait_method_with_default(&self) {}
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
fn trait_assoc_fn() {}
|
||||
}
|
||||
|
||||
trait HasAssocType {
|
||||
type T;
|
||||
fn constrain_assoc_type() -> Self::T;
|
||||
}
|
||||
|
||||
impl HasAssocType for () {
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
type T = impl Copy;
|
||||
fn constrain_assoc_type() -> Self::T {}
|
||||
}
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
struct MyStruct {
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
impl MyStruct {
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
fn method(&self) {}
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
fn assoc_fn() {}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
|
||||
static X: u32;
|
||||
|
||||
#[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
|
||||
type T;
|
||||
|
||||
#[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
|
||||
fn foreign_fn();
|
||||
}
|
||||
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
fn main() {
|
||||
#[sanitize(address = "off", thread = "on")] //~ ERROR sanitize attribute not allowed here
|
||||
let _ = ();
|
||||
|
||||
// Currently not allowed on let statements, even if they bind to a closure.
|
||||
// It might be nice to support this as a special case someday, but trying
|
||||
// to define the precise boundaries of that special case might be tricky.
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
let _let_closure = || ();
|
||||
|
||||
// In situations where attributes can already be applied to expressions,
|
||||
// the sanitize attribute is allowed on closure expressions.
|
||||
let _closure_tail_expr = {
|
||||
#[sanitize(address = "off", thread = "on")]
|
||||
|| ()
|
||||
};
|
||||
|
||||
match () {
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
() => (),
|
||||
}
|
||||
|
||||
#[sanitize(address = "off")] //~ ERROR sanitize attribute not allowed here
|
||||
return ();
|
||||
}
|
||||
190
tests/ui/sanitize-attr/valid-sanitize.stderr
Normal file
190
tests/ui/sanitize-attr/valid-sanitize.stderr
Normal file
@@ -0,0 +1,190 @@
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:15:1
|
||||
|
|
||||
LL | #[sanitize(thread = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | static BAR: u32 = 0;
|
||||
| -------------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:18:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | type MyTypeAlias = ();
|
||||
| ---------------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:21:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / trait MyTrait {
|
||||
LL | | #[sanitize(address = "off")]
|
||||
LL | | const TRAIT_ASSOC_CONST: u32;
|
||||
... |
|
||||
LL | | fn trait_assoc_fn();
|
||||
LL | | }
|
||||
| |_- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:65:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / struct MyStruct {
|
||||
LL | | #[sanitize(address = "off")]
|
||||
LL | | field: u32,
|
||||
LL | | }
|
||||
| |_- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:67:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | field: u32,
|
||||
| ---------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:92:5
|
||||
|
|
||||
LL | #[sanitize(address = "off", thread = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _ = ();
|
||||
| ----------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:98:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let _let_closure = || ();
|
||||
| ------------------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:109:9
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | () => (),
|
||||
| -------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:113:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | return ();
|
||||
| --------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:23:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | const TRAIT_ASSOC_CONST: u32;
|
||||
| ----------------------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:26:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | type TraitAssocType;
|
||||
| -------------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:29:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | fn trait_method(&self);
|
||||
| ----------------------- function has no body
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:35:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | fn trait_assoc_fn();
|
||||
| -------------------- function has no body
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:43:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | type TraitAssocType = Self;
|
||||
| --------------------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:60:5
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | type T = impl Copy;
|
||||
| ------------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:80:5
|
||||
|
|
||||
LL | #[sanitize(address = "off", thread = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | static X: u32;
|
||||
| -------------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:83:5
|
||||
|
|
||||
LL | #[sanitize(address = "off", thread = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | type T;
|
||||
| ------- not a function, impl block, or module
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: sanitize attribute not allowed here
|
||||
--> $DIR/valid-sanitize.rs:86:5
|
||||
|
|
||||
LL | #[sanitize(address = "off", thread = "on")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | fn foreign_fn();
|
||||
| ---------------- function has no body
|
||||
|
|
||||
= help: sanitize attribute can be applied to a function (with body), impl block, or module
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
15
tests/ui/sanitizer/inline-always-sanitize.rs
Normal file
15
tests/ui/sanitizer/inline-always-sanitize.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
//@ check-pass
|
||||
|
||||
#![feature(sanitize)]
|
||||
|
||||
#[inline(always)]
|
||||
//~^ NOTE inlining requested here
|
||||
#[sanitize(address = "off")]
|
||||
//~^ WARN setting `sanitize` off will have no effect after inlining
|
||||
//~| NOTE on by default
|
||||
fn x() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
x()
|
||||
}
|
||||
15
tests/ui/sanitizer/inline-always-sanitize.stderr
Normal file
15
tests/ui/sanitizer/inline-always-sanitize.stderr
Normal file
@@ -0,0 +1,15 @@
|
||||
warning: setting `sanitize` off will have no effect after inlining
|
||||
--> $DIR/inline-always-sanitize.rs:7:1
|
||||
|
|
||||
LL | #[sanitize(address = "off")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: inlining requested here
|
||||
--> $DIR/inline-always-sanitize.rs:5:1
|
||||
|
|
||||
LL | #[inline(always)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
= note: `#[warn(inline_no_sanitize)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//@ check-pass
|
||||
|
||||
#![feature(no_sanitize)]
|
||||
|
||||
#[inline(always)]
|
||||
//~^ NOTE inlining requested here
|
||||
#[no_sanitize(address)]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
warning: `no_sanitize` will have no effect after inlining
|
||||
--> $DIR/inline-always.rs:7:1
|
||||
--> $DIR/inline-always.rs:6:1
|
||||
|
|
||||
LL | #[no_sanitize(address)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: inlining requested here
|
||||
--> $DIR/inline-always.rs:5:1
|
||||
--> $DIR/inline-always.rs:4:1
|
||||
|
|
||||
LL | #[inline(always)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
Reference in New Issue
Block a user