Rollup merge of #127483 - BertalanD:no_sanitize-global-var, r=rcvalle
Allow disabling ASan instrumentation for globals AddressSanitizer adds instrumentation to global variables unless the [`no_sanitize_address`](https://llvm.org/docs/LangRef.html#global-attributes) attribute is set on them. This commit extends the existing `#[no_sanitize(address)]` attribute to set this; previously it only had the desired effect on functions. (cc https://github.com/rust-lang/rust/issues/39699)
This commit is contained in:
commit
c6d36256a6
10 changed files with 137 additions and 34 deletions
|
@ -172,3 +172,12 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
|
||||||
Visibility::Protected => llvm::Visibility::Protected,
|
Visibility::Protected => llvm::Visibility::Protected,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) {
|
||||||
|
if attrs.no_sanitize.contains(SanitizerSet::ADDRESS) {
|
||||||
|
unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) };
|
||||||
|
}
|
||||||
|
if attrs.no_sanitize.contains(SanitizerSet::HWADDRESS) {
|
||||||
|
unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -470,6 +470,8 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||||
base::set_link_section(g, attrs);
|
base::set_link_section(g, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::set_variable_sanitizer_attrs(g, attrs);
|
||||||
|
|
||||||
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
|
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
|
||||||
// `USED` and `USED_LINKER` can't be used together.
|
// `USED` and `USED_LINKER` can't be used together.
|
||||||
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
|
assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
|
||||||
|
|
|
@ -2460,4 +2460,7 @@ unsafe extern "C" {
|
||||||
pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool;
|
pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool;
|
||||||
|
|
||||||
pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool;
|
pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool;
|
||||||
|
|
||||||
|
pub fn LLVMRustSetNoSanitizeAddress(Global: &Value);
|
||||||
|
pub fn LLVMRustSetNoSanitizeHWAddress(Global: &Value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2051,6 +2051,25 @@ extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
|
||||||
return llvm::compression::zstd::isAvailable();
|
return llvm::compression::zstd::isAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" void LLVMRustSetNoSanitizeAddress(LLVMValueRef Global) {
|
||||||
|
GlobalValue &GV = *unwrap<GlobalValue>(Global);
|
||||||
|
GlobalValue::SanitizerMetadata MD;
|
||||||
|
if (GV.hasSanitizerMetadata())
|
||||||
|
MD = GV.getSanitizerMetadata();
|
||||||
|
MD.NoAddress = true;
|
||||||
|
MD.IsDynInit = false;
|
||||||
|
GV.setSanitizerMetadata(MD);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
|
||||||
|
GlobalValue &GV = *unwrap<GlobalValue>(Global);
|
||||||
|
GlobalValue::SanitizerMetadata MD;
|
||||||
|
if (GV.hasSanitizerMetadata())
|
||||||
|
MD = GV.getSanitizerMetadata();
|
||||||
|
MD.NoHWAddress = true;
|
||||||
|
GV.setSanitizerMetadata(MD);
|
||||||
|
}
|
||||||
|
|
||||||
// Operations on composite constants.
|
// Operations on composite constants.
|
||||||
// These are clones of LLVM api functions that will become available in future
|
// These are clones of LLVM api functions that will become available in future
|
||||||
// releases. They can be removed once Rust's minimum supported LLVM version
|
// releases. They can be removed once Rust's minimum supported LLVM version
|
||||||
|
|
|
@ -558,6 +558,10 @@ passes_no_mangle_foreign =
|
||||||
passes_no_patterns =
|
passes_no_patterns =
|
||||||
patterns not allowed in naked function parameters
|
patterns not allowed in naked function parameters
|
||||||
|
|
||||||
|
passes_no_sanitize =
|
||||||
|
`#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
|
||||||
|
.label = not {$accepted_kind}
|
||||||
|
|
||||||
passes_non_exported_macro_invalid_attrs =
|
passes_non_exported_macro_invalid_attrs =
|
||||||
attribute should be applied to function or closure
|
attribute should be applied to function or closure
|
||||||
.label = not a function or closure
|
.label = not a function or closure
|
||||||
|
|
|
@ -126,9 +126,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
[sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
|
[sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
|
||||||
[sym::coverage, ..] => self.check_coverage(attr, span, target),
|
[sym::coverage, ..] => self.check_coverage(attr, span, target),
|
||||||
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
|
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
|
||||||
[sym::no_sanitize, ..] => {
|
[sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target),
|
||||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
|
||||||
}
|
|
||||||
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
|
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
|
||||||
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
|
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
|
||||||
[sym::target_feature, ..] => {
|
[sym::target_feature, ..] => {
|
||||||
|
@ -450,6 +448,39 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
|
||||||
|
if let Some(list) = attr.meta_item_list() {
|
||||||
|
for item in list.iter() {
|
||||||
|
let sym = item.name_or_empty();
|
||||||
|
match sym {
|
||||||
|
sym::address | sym::hwaddress => {
|
||||||
|
let is_valid =
|
||||||
|
matches!(target, Target::Fn | Target::Method(..) | Target::Static);
|
||||||
|
if !is_valid {
|
||||||
|
self.dcx().emit_err(errors::NoSanitize {
|
||||||
|
attr_span: item.span(),
|
||||||
|
defn_span: span,
|
||||||
|
accepted_kind: "a function or static",
|
||||||
|
attr_str: sym.as_str(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let is_valid = matches!(target, Target::Fn | Target::Method(..));
|
||||||
|
if !is_valid {
|
||||||
|
self.dcx().emit_err(errors::NoSanitize {
|
||||||
|
attr_span: item.span(),
|
||||||
|
defn_span: span,
|
||||||
|
accepted_kind: "a function",
|
||||||
|
attr_str: sym.as_str(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_generic_attr(
|
fn check_generic_attr(
|
||||||
&self,
|
&self,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
|
|
|
@ -1846,3 +1846,14 @@ pub(crate) struct AttrCrateLevelOnlySugg {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub attr: Span,
|
pub attr: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(passes_no_sanitize)]
|
||||||
|
pub(crate) struct NoSanitize<'a> {
|
||||||
|
#[primary_span]
|
||||||
|
pub attr_span: Span,
|
||||||
|
#[label]
|
||||||
|
pub defn_span: Span,
|
||||||
|
pub accepted_kind: &'a str,
|
||||||
|
pub attr_str: &'a str,
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,16 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![feature(no_sanitize)]
|
#![feature(no_sanitize)]
|
||||||
|
|
||||||
|
// CHECK: @UNSANITIZED = constant{{.*}} no_sanitize_address
|
||||||
|
// CHECK-NOT: @__asan_global_UNSANITIZED
|
||||||
|
#[no_mangle]
|
||||||
|
#[no_sanitize(address)]
|
||||||
|
pub static UNSANITIZED: u32 = 0;
|
||||||
|
|
||||||
|
// CHECK: @__asan_global_SANITIZED
|
||||||
|
#[no_mangle]
|
||||||
|
pub static SANITIZED: u32 = 0;
|
||||||
|
|
||||||
// CHECK-LABEL: ; no_sanitize::unsanitized
|
// CHECK-LABEL: ; no_sanitize::unsanitized
|
||||||
// CHECK-NEXT: ; Function Attrs:
|
// CHECK-NEXT: ; Function Attrs:
|
||||||
// CHECK-NOT: sanitize_address
|
// CHECK-NOT: sanitize_address
|
||||||
|
|
|
@ -4,31 +4,37 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
fn invalid() {
|
fn invalid() {
|
||||||
#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
|
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
|
||||||
{
|
{
|
||||||
1
|
1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
|
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
|
||||||
type InvalidTy = ();
|
type InvalidTy = ();
|
||||||
|
|
||||||
#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
|
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
|
||||||
mod invalid_module {}
|
mod invalid_module {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = #[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
|
let _ = #[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
|
||||||
(|| 1);
|
(|| 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
|
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
|
||||||
struct F;
|
struct F;
|
||||||
|
|
||||||
#[no_sanitize(memory)] //~ ERROR attribute should be applied to a function definition
|
#[no_sanitize(memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
|
||||||
impl F {
|
impl F {
|
||||||
#[no_sanitize(memory)]
|
#[no_sanitize(memory)]
|
||||||
fn valid(&self) {}
|
fn valid(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_sanitize(address, memory)] //~ ERROR `#[no_sanitize(memory)]` should be applied to a function
|
||||||
|
static INVALID : i32 = 0;
|
||||||
|
|
||||||
#[no_sanitize(memory)]
|
#[no_sanitize(memory)]
|
||||||
fn valid() {}
|
fn valid() {}
|
||||||
|
|
||||||
|
#[no_sanitize(address)]
|
||||||
|
static VALID : i32 = 0;
|
||||||
|
|
|
@ -1,55 +1,63 @@
|
||||||
error: attribute should be applied to a function definition
|
error: `#[no_sanitize(memory)]` should be applied to a function
|
||||||
--> $DIR/no-sanitize.rs:7:5
|
--> $DIR/no-sanitize.rs:7:19
|
||||||
|
|
|
|
||||||
LL | #[no_sanitize(memory)]
|
LL | #[no_sanitize(memory)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^
|
||||||
LL | / {
|
LL | / {
|
||||||
LL | | 1
|
LL | | 1
|
||||||
LL | | };
|
LL | | };
|
||||||
| |_____- not a function definition
|
| |_____- not a function
|
||||||
|
|
||||||
error: attribute should be applied to a function definition
|
error: `#[no_sanitize(memory)]` should be applied to a function
|
||||||
--> $DIR/no-sanitize.rs:13:1
|
--> $DIR/no-sanitize.rs:13:15
|
||||||
|
|
|
|
||||||
LL | #[no_sanitize(memory)]
|
LL | #[no_sanitize(memory)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^
|
||||||
LL | type InvalidTy = ();
|
LL | type InvalidTy = ();
|
||||||
| -------------------- not a function definition
|
| -------------------- not a function
|
||||||
|
|
||||||
error: attribute should be applied to a function definition
|
error: `#[no_sanitize(memory)]` should be applied to a function
|
||||||
--> $DIR/no-sanitize.rs:16:1
|
--> $DIR/no-sanitize.rs:16:15
|
||||||
|
|
|
|
||||||
LL | #[no_sanitize(memory)]
|
LL | #[no_sanitize(memory)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^
|
||||||
LL | mod invalid_module {}
|
LL | mod invalid_module {}
|
||||||
| --------------------- not a function definition
|
| --------------------- not a function
|
||||||
|
|
||||||
error: attribute should be applied to a function definition
|
error: `#[no_sanitize(memory)]` should be applied to a function
|
||||||
--> $DIR/no-sanitize.rs:20:13
|
--> $DIR/no-sanitize.rs:20:27
|
||||||
|
|
|
|
||||||
LL | let _ = #[no_sanitize(memory)]
|
LL | let _ = #[no_sanitize(memory)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^
|
||||||
LL | (|| 1);
|
LL | (|| 1);
|
||||||
| ------ not a function definition
|
| ------ not a function
|
||||||
|
|
||||||
error: attribute should be applied to a function definition
|
error: `#[no_sanitize(memory)]` should be applied to a function
|
||||||
--> $DIR/no-sanitize.rs:24:1
|
--> $DIR/no-sanitize.rs:24:15
|
||||||
|
|
|
|
||||||
LL | #[no_sanitize(memory)]
|
LL | #[no_sanitize(memory)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^
|
||||||
LL | struct F;
|
LL | struct F;
|
||||||
| --------- not a function definition
|
| --------- not a function
|
||||||
|
|
||||||
error: attribute should be applied to a function definition
|
error: `#[no_sanitize(memory)]` should be applied to a function
|
||||||
--> $DIR/no-sanitize.rs:27:1
|
--> $DIR/no-sanitize.rs:27:15
|
||||||
|
|
|
|
||||||
LL | #[no_sanitize(memory)]
|
LL | #[no_sanitize(memory)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^
|
||||||
LL | / impl F {
|
LL | / impl F {
|
||||||
LL | | #[no_sanitize(memory)]
|
LL | | #[no_sanitize(memory)]
|
||||||
LL | | fn valid(&self) {}
|
LL | | fn valid(&self) {}
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_- not a function definition
|
| |_- not a function
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: `#[no_sanitize(memory)]` should be applied to a function
|
||||||
|
--> $DIR/no-sanitize.rs:33:24
|
||||||
|
|
|
||||||
|
LL | #[no_sanitize(address, memory)]
|
||||||
|
| ^^^^^^
|
||||||
|
LL | static INVALID : i32 = 0;
|
||||||
|
| ------------------------- not a function
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue