mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
Selectively disable sanitizer instrumentation
Add `no_sanitize` attribute that allows to opt out from sanitizer instrumentation in an annotated function.
This commit is contained in:
parent
eda1a7adfc
commit
b846b42c8d
29
src/doc/unstable-book/src/language-features/no-sanitize.md
Normal file
29
src/doc/unstable-book/src/language-features/no-sanitize.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# `no_sanitize`
|
||||||
|
|
||||||
|
The tracking issue for this feature is: [#39699]
|
||||||
|
|
||||||
|
[#39699]: https://github.com/rust-lang/rust/issues/39699
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The `no_sanitize` attribute can be used to selectively disable sanitizer
|
||||||
|
instrumentation in an annotated function. This might be useful to: avoid
|
||||||
|
instrumentation overhead in a performance critical function, or avoid
|
||||||
|
instrumenting code that contains constructs unsupported by given sanitizer.
|
||||||
|
|
||||||
|
The precise effect of this annotation depends on particular sanitizer in use.
|
||||||
|
For example, with `no_sanitize(thread)`, the thread sanitizer will no longer
|
||||||
|
instrument non-atomic store / load operations, but it will instrument atomic
|
||||||
|
operations to avoid reporting false positives and provide meaning full stack
|
||||||
|
traces.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
#![feature(no_sanitize)]
|
||||||
|
|
||||||
|
#[no_sanitize(address)]
|
||||||
|
fn foo() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
@ -72,6 +72,12 @@ bitflags! {
|
|||||||
const FFI_RETURNS_TWICE = 1 << 10;
|
const FFI_RETURNS_TWICE = 1 << 10;
|
||||||
/// `#[track_caller]`: allow access to the caller location
|
/// `#[track_caller]`: allow access to the caller location
|
||||||
const TRACK_CALLER = 1 << 11;
|
const TRACK_CALLER = 1 << 11;
|
||||||
|
/// `#[no_sanitize(address)]`: disables address sanitizer instrumentation
|
||||||
|
const NO_SANITIZE_ADDRESS = 1 << 12;
|
||||||
|
/// `#[no_sanitize(memory)]`: disables memory sanitizer instrumentation
|
||||||
|
const NO_SANITIZE_MEMORY = 1 << 13;
|
||||||
|
/// `#[no_sanitize(thread)]`: disables thread sanitizer instrumentation
|
||||||
|
const NO_SANITIZE_THREAD = 1 << 14;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,6 +288,26 @@ pub fn from_fn_attrs(
|
|||||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
|
||||||
Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
|
Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn);
|
||||||
}
|
}
|
||||||
|
if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer {
|
||||||
|
match *sanitizer {
|
||||||
|
Sanitizer::Address => {
|
||||||
|
if !codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
|
||||||
|
llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sanitizer::Memory => {
|
||||||
|
if !codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
|
||||||
|
llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sanitizer::Thread => {
|
||||||
|
if !codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
|
||||||
|
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sanitizer::Leak => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unwind(
|
unwind(
|
||||||
llfn,
|
llfn,
|
||||||
|
@ -19,7 +19,6 @@ use crate::llvm::AttributePlace::Function;
|
|||||||
use crate::type_::Type;
|
use crate::type_::Type;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rustc::session::config::Sanitizer;
|
|
||||||
use rustc::ty::Ty;
|
use rustc::ty::Ty;
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
use rustc_data_structures::small_c_str::SmallCStr;
|
use rustc_data_structures::small_c_str::SmallCStr;
|
||||||
@ -47,21 +46,6 @@ fn declare_raw_fn(
|
|||||||
llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
|
llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer {
|
|
||||||
match *sanitizer {
|
|
||||||
Sanitizer::Address => {
|
|
||||||
llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn);
|
|
||||||
}
|
|
||||||
Sanitizer::Memory => {
|
|
||||||
llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn);
|
|
||||||
}
|
|
||||||
Sanitizer::Thread => {
|
|
||||||
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes::default_optimisation_attrs(cx.tcx.sess, llfn);
|
attributes::default_optimisation_attrs(cx.tcx.sess, llfn);
|
||||||
attributes::non_lazy_bind(cx.sess(), llfn);
|
attributes::non_lazy_bind(cx.sess(), llfn);
|
||||||
llfn
|
llfn
|
||||||
|
@ -541,6 +541,9 @@ declare_features! (
|
|||||||
/// Allows `T: ?const Trait` syntax in bounds.
|
/// Allows `T: ?const Trait` syntax in bounds.
|
||||||
(active, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
|
(active, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
|
||||||
|
|
||||||
|
/// Allows the use of `no_sanitize` attribute.
|
||||||
|
(active, no_sanitize, "1.42.0", Some(39699), None),
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// feature-group-end: actual feature gates
|
// feature-group-end: actual feature gates
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
@ -261,6 +261,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
ungated!(cold, Whitelisted, template!(Word)),
|
ungated!(cold, Whitelisted, template!(Word)),
|
||||||
ungated!(no_builtins, Whitelisted, template!(Word)),
|
ungated!(no_builtins, Whitelisted, template!(Word)),
|
||||||
ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)),
|
ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)),
|
||||||
|
gated!(
|
||||||
|
no_sanitize, Whitelisted,
|
||||||
|
template!(List: "address, memory, thread"),
|
||||||
|
experimental!(no_sanitize)
|
||||||
|
),
|
||||||
|
|
||||||
// FIXME: #14408 whitelist docs since rustdoc looks at them
|
// FIXME: #14408 whitelist docs since rustdoc looks at them
|
||||||
ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")),
|
ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")),
|
||||||
|
@ -8,6 +8,7 @@ use rustc_index::vec::{Idx, IndexVec};
|
|||||||
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use rustc::mir::visit::*;
|
use rustc::mir::visit::*;
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
|
use rustc::session::config::Sanitizer;
|
||||||
use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||||
use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
|
use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
|
||||||
|
|
||||||
@ -228,6 +229,28 @@ impl Inliner<'tcx> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid inlining functions marked as no_sanitize if sanitizer is enabled,
|
||||||
|
// since instrumentation might be enabled and performed on the caller.
|
||||||
|
match self.tcx.sess.opts.debugging_opts.sanitizer {
|
||||||
|
Some(Sanitizer::Address) => {
|
||||||
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(Sanitizer::Memory) => {
|
||||||
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(Sanitizer::Thread) => {
|
||||||
|
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(Sanitizer::Leak) => {}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
let hinted = match codegen_fn_attrs.inline {
|
let hinted = match codegen_fn_attrs.inline {
|
||||||
// Just treat inline(always) as a hint for now,
|
// Just treat inline(always) as a hint for now,
|
||||||
// there are cases that prevent inlining that we
|
// there are cases that prevent inlining that we
|
||||||
|
@ -474,6 +474,12 @@ declare_lint! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
pub INLINE_NO_SANITIZE,
|
||||||
|
Warn,
|
||||||
|
"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`",
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint_pass! {
|
declare_lint_pass! {
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
/// that are used by other parts of the compiler.
|
/// that are used by other parts of the compiler.
|
||||||
@ -537,5 +543,6 @@ declare_lint_pass! {
|
|||||||
MUTABLE_BORROW_RESERVATION_CONFLICT,
|
MUTABLE_BORROW_RESERVATION_CONFLICT,
|
||||||
INDIRECT_STRUCTURAL_MATCH,
|
INDIRECT_STRUCTURAL_MATCH,
|
||||||
SOFT_UNSTABLE,
|
SOFT_UNSTABLE,
|
||||||
|
INLINE_NO_SANITIZE,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,7 @@ symbols! {
|
|||||||
abi_vectorcall,
|
abi_vectorcall,
|
||||||
abi_x86_interrupt,
|
abi_x86_interrupt,
|
||||||
aborts,
|
aborts,
|
||||||
|
address,
|
||||||
add_with_overflow,
|
add_with_overflow,
|
||||||
advanced_slice_patterns,
|
advanced_slice_patterns,
|
||||||
adx_target_feature,
|
adx_target_feature,
|
||||||
@ -445,6 +446,7 @@ symbols! {
|
|||||||
mem_uninitialized,
|
mem_uninitialized,
|
||||||
mem_zeroed,
|
mem_zeroed,
|
||||||
member_constraints,
|
member_constraints,
|
||||||
|
memory,
|
||||||
message,
|
message,
|
||||||
meta,
|
meta,
|
||||||
min_align_of,
|
min_align_of,
|
||||||
@ -487,6 +489,7 @@ symbols! {
|
|||||||
None,
|
None,
|
||||||
non_exhaustive,
|
non_exhaustive,
|
||||||
non_modrs_mods,
|
non_modrs_mods,
|
||||||
|
no_sanitize,
|
||||||
no_stack_check,
|
no_stack_check,
|
||||||
no_start,
|
no_start,
|
||||||
no_std,
|
no_std,
|
||||||
@ -721,6 +724,7 @@ symbols! {
|
|||||||
test_removed_feature,
|
test_removed_feature,
|
||||||
test_runner,
|
test_runner,
|
||||||
then_with,
|
then_with,
|
||||||
|
thread,
|
||||||
thread_local,
|
thread_local,
|
||||||
tool_attributes,
|
tool_attributes,
|
||||||
tool_lints,
|
tool_lints,
|
||||||
|
@ -2743,6 +2743,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
|
|
||||||
let mut inline_span = None;
|
let mut inline_span = None;
|
||||||
let mut link_ordinal_span = None;
|
let mut link_ordinal_span = None;
|
||||||
|
let mut no_sanitize_span = None;
|
||||||
for attr in attrs.iter() {
|
for attr in attrs.iter() {
|
||||||
if attr.check_name(sym::cold) {
|
if attr.check_name(sym::cold) {
|
||||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
|
||||||
@ -2832,6 +2833,24 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
|
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
|
||||||
codegen_fn_attrs.link_ordinal = ordinal;
|
codegen_fn_attrs.link_ordinal = ordinal;
|
||||||
}
|
}
|
||||||
|
} else if attr.check_name(sym::no_sanitize) {
|
||||||
|
no_sanitize_span = Some(attr.span);
|
||||||
|
if let Some(list) = attr.meta_item_list() {
|
||||||
|
for item in list.iter() {
|
||||||
|
if item.check_name(sym::address) {
|
||||||
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_ADDRESS;
|
||||||
|
} else if item.check_name(sym::memory) {
|
||||||
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_MEMORY;
|
||||||
|
} else if item.check_name(sym::thread) {
|
||||||
|
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_THREAD;
|
||||||
|
} else {
|
||||||
|
tcx.sess
|
||||||
|
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
|
||||||
|
.note("expected one of: `address`, `memory` or `thread`")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2911,7 +2930,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
// purpose functions as they wouldn't have the right target features
|
// purpose functions as they wouldn't have the right target features
|
||||||
// enabled. For that reason we also forbid #[inline(always)] as it can't be
|
// enabled. For that reason we also forbid #[inline(always)] as it can't be
|
||||||
// respected.
|
// respected.
|
||||||
|
|
||||||
if codegen_fn_attrs.target_features.len() > 0 {
|
if codegen_fn_attrs.target_features.len() > 0 {
|
||||||
if codegen_fn_attrs.inline == InlineAttr::Always {
|
if codegen_fn_attrs.inline == InlineAttr::Always {
|
||||||
if let Some(span) = inline_span {
|
if let Some(span) = inline_span {
|
||||||
@ -2924,6 +2942,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let no_sanitize_flags = CodegenFnAttrFlags::NO_SANITIZE_ADDRESS
|
||||||
|
| CodegenFnAttrFlags::NO_SANITIZE_MEMORY
|
||||||
|
| CodegenFnAttrFlags::NO_SANITIZE_THREAD;
|
||||||
|
if codegen_fn_attrs.flags.intersects(no_sanitize_flags) {
|
||||||
|
if codegen_fn_attrs.inline == InlineAttr::Always {
|
||||||
|
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
|
||||||
|
let hir_id = tcx.hir().as_local_hir_id(id).unwrap();
|
||||||
|
tcx.struct_span_lint_hir(
|
||||||
|
lint::builtin::INLINE_NO_SANITIZE,
|
||||||
|
hir_id,
|
||||||
|
no_sanitize_span,
|
||||||
|
"`no_sanitize` will have no effect after inlining",
|
||||||
|
)
|
||||||
|
.span_note(inline_span, "inlining requested here")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Weak lang items have the same semantics as "std internal" symbols in the
|
// Weak lang items have the same semantics as "std internal" symbols in the
|
||||||
// sense that they're preserved through all our LTO passes and only
|
// sense that they're preserved through all our LTO passes and only
|
||||||
// strippable by the linker.
|
// strippable by the linker.
|
||||||
|
32
src/test/codegen/sanitizer-no-sanitize-inlining.rs
Normal file
32
src/test/codegen/sanitizer-no-sanitize-inlining.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Verifies that no_sanitize attribute prevents inlining when
|
||||||
|
// given sanitizer is enabled, but has no effect on inlining otherwise.
|
||||||
|
//
|
||||||
|
// needs-sanitizer-support
|
||||||
|
// only-x86_64
|
||||||
|
//
|
||||||
|
// revisions: ASAN LSAN
|
||||||
|
//
|
||||||
|
//[ASAN] compile-flags: -Zsanitizer=address -C opt-level=3 -Z mir-opt-level=3
|
||||||
|
//[LSAN] compile-flags: -Zsanitizer=leak -C opt-level=3 -Z mir-opt-level=3
|
||||||
|
|
||||||
|
#![crate_type="lib"]
|
||||||
|
#![feature(no_sanitize)]
|
||||||
|
|
||||||
|
// ASAN-LABEL: define void @test
|
||||||
|
// ASAN: tail call fastcc void @random_inline
|
||||||
|
// ASAN: }
|
||||||
|
//
|
||||||
|
// LSAN-LABEL: define void @test
|
||||||
|
// LSAN-NO: call
|
||||||
|
// LSAN: }
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn test(n: &mut u32) {
|
||||||
|
random_inline(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_sanitize(address)]
|
||||||
|
#[inline]
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn random_inline(n: &mut u32) {
|
||||||
|
*n = 42;
|
||||||
|
}
|
29
src/test/codegen/sanitizer-no-sanitize.rs
Normal file
29
src/test/codegen/sanitizer-no-sanitize.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Verifies that no_sanitze attribute can be used to
|
||||||
|
// selectively disable sanitizer instrumentation.
|
||||||
|
//
|
||||||
|
// needs-sanitizer-support
|
||||||
|
// compile-flags: -Zsanitizer=address
|
||||||
|
|
||||||
|
#![crate_type="lib"]
|
||||||
|
#![feature(no_sanitize)]
|
||||||
|
|
||||||
|
// CHECK-LABEL: ; sanitizer_no_sanitize::unsanitized
|
||||||
|
// CHECK-NEXT: ; Function Attrs:
|
||||||
|
// CHECK-NOT: sanitize_address
|
||||||
|
// CHECK: start:
|
||||||
|
// CHECK-NOT: call void @__asan_report_load
|
||||||
|
// CHECK: }
|
||||||
|
#[no_sanitize(address)]
|
||||||
|
pub fn unsanitized(b: &mut u8) -> u8 {
|
||||||
|
*b
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: ; sanitizer_no_sanitize::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
|
||||||
|
}
|
4
src/test/ui/feature-gates/feature-gate-no_sanitize.rs
Normal file
4
src/test/ui/feature-gates/feature-gate-no_sanitize.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#[no_sanitize(address)]
|
||||||
|
//~^ the `#[no_sanitize]` attribute is an experimental feature
|
||||||
|
fn main() {
|
||||||
|
}
|
12
src/test/ui/feature-gates/feature-gate-no_sanitize.stderr
Normal file
12
src/test/ui/feature-gates/feature-gate-no_sanitize.stderr
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
error[E0658]: the `#[no_sanitize]` attribute is an experimental feature
|
||||||
|
--> $DIR/feature-gate-no_sanitize.rs:1:1
|
||||||
|
|
|
||||||
|
LL | #[no_sanitize(address)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: for more information, see https://github.com/rust-lang/rust/issues/39699
|
||||||
|
= help: add `#![feature(no_sanitize)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
5
src/test/ui/invalid/invalid-no-sanitize.rs
Normal file
5
src/test/ui/invalid/invalid-no-sanitize.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#![feature(no_sanitize)]
|
||||||
|
|
||||||
|
#[no_sanitize(brontosaurus)] //~ ERROR invalid argument
|
||||||
|
fn main() {
|
||||||
|
}
|
10
src/test/ui/invalid/invalid-no-sanitize.stderr
Normal file
10
src/test/ui/invalid/invalid-no-sanitize.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
error: invalid argument for `no_sanitize`
|
||||||
|
--> $DIR/invalid-no-sanitize.rs:3:15
|
||||||
|
|
|
||||||
|
LL | #[no_sanitize(brontosaurus)]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: expected one of: `address`, `memory` or `thread`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
15
src/test/ui/sanitize-inline-always.rs
Normal file
15
src/test/ui/sanitize-inline-always.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(no_sanitize)]
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
//~^ NOTE inlining requested here
|
||||||
|
#[no_sanitize(address)]
|
||||||
|
//~^ WARN will have no effect after inlining
|
||||||
|
//~| NOTE on by default
|
||||||
|
fn x() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
x()
|
||||||
|
}
|
13
src/test/ui/sanitize-inline-always.stderr
Normal file
13
src/test/ui/sanitize-inline-always.stderr
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
warning: `no_sanitize` will have no effect after inlining
|
||||||
|
--> $DIR/sanitize-inline-always.rs:7:1
|
||||||
|
|
|
||||||
|
LL | #[no_sanitize(address)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(inline_no_sanitize)]` on by default
|
||||||
|
note: inlining requested here
|
||||||
|
--> $DIR/sanitize-inline-always.rs:5:1
|
||||||
|
|
|
||||||
|
LL | #[inline(always)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
Loading…
Reference in New Issue
Block a user