HWASan support
This commit is contained in:
parent
0b7a598e12
commit
c7d9bffe76
18 changed files with 100 additions and 12 deletions
|
@ -53,6 +53,9 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V
|
|||
if enabled.contains(SanitizerSet::THREAD) {
|
||||
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
|
||||
}
|
||||
if enabled.contains(SanitizerSet::HWADDRESS) {
|
||||
llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
|
||||
|
|
|
@ -440,6 +440,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
|
|||
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
|
||||
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
|
||||
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
|
||||
sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
|
||||
sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -652,6 +654,10 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
|
|||
if config.sanitizer.contains(SanitizerSet::THREAD) {
|
||||
passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
|
||||
}
|
||||
if config.sanitizer.contains(SanitizerSet::HWADDRESS) {
|
||||
let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS);
|
||||
passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn link(
|
||||
|
|
|
@ -131,6 +131,7 @@ pub enum Attribute {
|
|||
ReturnsTwice = 25,
|
||||
ReadNone = 26,
|
||||
InaccessibleMemOnly = 27,
|
||||
SanitizeHWAddress = 28,
|
||||
}
|
||||
|
||||
/// LLVMIntPredicate
|
||||
|
@ -439,6 +440,8 @@ pub struct SanitizerOptions {
|
|||
pub sanitize_memory_recover: bool,
|
||||
pub sanitize_memory_track_origins: c_int,
|
||||
pub sanitize_thread: bool,
|
||||
pub sanitize_hwaddress: bool,
|
||||
pub sanitize_hwaddress_recover: bool,
|
||||
}
|
||||
|
||||
/// LLVMRelocMode
|
||||
|
@ -2128,6 +2131,7 @@ extern "C" {
|
|||
Recover: bool,
|
||||
) -> &'static mut Pass;
|
||||
pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass;
|
||||
pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
|
||||
pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
|
||||
pub fn LLVMRustAddLastExtensionPasses(
|
||||
PMB: &PassManagerBuilder,
|
||||
|
|
|
@ -893,6 +893,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
|
|||
if sanitizer.contains(SanitizerSet::THREAD) {
|
||||
link_sanitizer_runtime(sess, linker, "tsan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::HWADDRESS) {
|
||||
link_sanitizer_runtime(sess, linker, "hwasan");
|
||||
}
|
||||
}
|
||||
|
||||
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
|
||||
|
|
|
@ -85,6 +85,7 @@ enum LLVMRustAttribute {
|
|||
ReturnsTwice = 25,
|
||||
ReadNone = 26,
|
||||
InaccessibleMemOnly = 27,
|
||||
SanitizeHWAddress = 28,
|
||||
};
|
||||
|
||||
typedef struct OpaqueRustString *RustStringRef;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "llvm/Support/TimeProfiler.h"
|
||||
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
|
||||
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
|
||||
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
|
||||
|
||||
|
@ -133,6 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
|
|||
return wrap(createThreadSanitizerLegacyPassPass());
|
||||
}
|
||||
|
||||
extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
|
||||
const bool CompileKernel = false;
|
||||
|
||||
return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
|
||||
}
|
||||
|
||||
extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
|
||||
assert(RustPass);
|
||||
Pass *Pass = unwrap(RustPass);
|
||||
|
@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions {
|
|||
bool SanitizeMemoryRecover;
|
||||
int SanitizeMemoryTrackOrigins;
|
||||
bool SanitizeThread;
|
||||
bool SanitizeHWAddress;
|
||||
bool SanitizeHWAddressRecover;
|
||||
};
|
||||
|
||||
extern "C" void
|
||||
|
@ -886,6 +895,23 @@ LLVMRustOptimizeWithNewPassManager(
|
|||
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
|
||||
}
|
||||
);
|
||||
#endif
|
||||
}
|
||||
if (SanitizerOptions->SanitizeHWAddress) {
|
||||
#if LLVM_VERSION_GE(11, 0)
|
||||
OptimizerLastEPCallbacks.push_back(
|
||||
[SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
|
||||
MPM.addPass(HWAddressSanitizerPass(
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
|
||||
}
|
||||
);
|
||||
#else
|
||||
PipelineStartEPCallbacks.push_back(
|
||||
[SanitizerOptions](ModulePassManager &MPM) {
|
||||
MPM.addPass(HWAddressSanitizerPass(
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
|
||||
}
|
||||
);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,6 +205,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
|
|||
return Attribute::ReadNone;
|
||||
case InaccessibleMemOnly:
|
||||
return Attribute::InaccessibleMemOnly;
|
||||
case SanitizeHWAddress:
|
||||
return Attribute::SanitizeHWAddress;
|
||||
}
|
||||
report_fatal_error("bad AttributeKind");
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ bitflags! {
|
|||
const LEAK = 1 << 1;
|
||||
const MEMORY = 1 << 2;
|
||||
const THREAD = 1 << 3;
|
||||
const HWADDRESS = 1 << 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +57,7 @@ impl fmt::Display for SanitizerSet {
|
|||
SanitizerSet::LEAK => "leak",
|
||||
SanitizerSet::MEMORY => "memory",
|
||||
SanitizerSet::THREAD => "thread",
|
||||
SanitizerSet::HWADDRESS => "hwaddress",
|
||||
_ => panic!("unrecognized sanitizer {:?}", s),
|
||||
};
|
||||
if !first {
|
||||
|
@ -73,12 +75,18 @@ impl IntoIterator for SanitizerSet {
|
|||
type IntoIter = std::vec::IntoIter<SanitizerSet>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
[SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|&s| self.contains(s))
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
[
|
||||
SanitizerSet::ADDRESS,
|
||||
SanitizerSet::LEAK,
|
||||
SanitizerSet::MEMORY,
|
||||
SanitizerSet::THREAD,
|
||||
SanitizerSet::HWADDRESS,
|
||||
]
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|&s| self.contains(s))
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ macro_rules! options {
|
|||
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
||||
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
||||
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
|
||||
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
|
||||
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
|
||||
pub const parse_cfguard: &str =
|
||||
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
|
||||
|
@ -476,6 +476,7 @@ macro_rules! options {
|
|||
"leak" => SanitizerSet::LEAK,
|
||||
"memory" => SanitizerSet::MEMORY,
|
||||
"thread" => SanitizerSet::THREAD,
|
||||
"hwaddress" => SanitizerSet::HWADDRESS,
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1126,7 +1126,8 @@ impl Session {
|
|||
self.opts.optimize != config::OptLevel::No
|
||||
// AddressSanitizer uses lifetimes to detect use after scope bugs.
|
||||
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
|
||||
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
|
||||
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
|
||||
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
|
||||
}
|
||||
|
||||
pub fn link_dead_code(&self) -> bool {
|
||||
|
@ -1562,6 +1563,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
"x86_64-unknown-freebsd",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
];
|
||||
const HWASAN_SUPPORTED_TARGETS: &[&str] =
|
||||
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
|
||||
|
||||
// Sanitizers can only be used on some tested platforms.
|
||||
for s in sess.opts.debugging_opts.sanitizer {
|
||||
|
@ -1570,6 +1573,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||
SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
|
||||
SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
|
||||
SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
|
||||
SanitizerSet::HWADDRESS => HWASAN_SUPPORTED_TARGETS,
|
||||
_ => panic!("unrecognized sanitizer {}", s),
|
||||
};
|
||||
if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
|
||||
|
|
|
@ -593,6 +593,7 @@ symbols! {
|
|||
html_no_source,
|
||||
html_playground_url,
|
||||
html_root_url,
|
||||
hwaddress,
|
||||
i,
|
||||
i128,
|
||||
i128_type,
|
||||
|
|
|
@ -2628,10 +2628,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
|
|||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
|
||||
} else if item.has_name(sym::thread) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
|
||||
} else if item.has_name(sym::hwaddress) {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
|
||||
} else {
|
||||
tcx.sess
|
||||
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
|
||||
.note("expected one of: `address`, `memory` or `thread`")
|
||||
.note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ o("option-checking", None, "complain about unrecognized options in this configur
|
|||
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
|
||||
o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
|
||||
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
|
||||
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)")
|
||||
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
|
||||
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
|
||||
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
|
||||
o("profiler", "build.profiler", "build the profiler runtime")
|
||||
|
|
|
@ -804,7 +804,7 @@ fn supported_sanitizers(
|
|||
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
|
||||
"aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
|
||||
"aarch64-unknown-linux-gnu" => {
|
||||
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
|
||||
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
|
||||
}
|
||||
"x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
|
||||
"x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
|
||||
|
|
|
@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
|
|||
LL | #[no_sanitize(brontosaurus)]
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: expected one of: `address`, `memory` or `thread`
|
||||
= note: expected one of: `address`, `hwaddress`, `memory` or `thread`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
19
src/test/ui/sanitize/hwaddress.rs
Normal file
19
src/test/ui/sanitize/hwaddress.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// needs-sanitizer-support
|
||||
// needs-sanitizer-hwaddress
|
||||
//
|
||||
// compile-flags: -Z sanitizer=hwaddress -O -g
|
||||
//
|
||||
// run-fail
|
||||
// error-pattern: HWAddressSanitizer: tag-mismatch
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
use std::hint::black_box;
|
||||
|
||||
fn main() {
|
||||
let xs = vec![0, 1, 2, 3];
|
||||
// Avoid optimizing everything out.
|
||||
let xs = black_box(xs.as_ptr());
|
||||
let code = unsafe { *xs.offset(4) };
|
||||
std::process::exit(code);
|
||||
}
|
|
@ -48,6 +48,7 @@ impl EarlyProps {
|
|||
let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
||||
let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
||||
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
||||
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
||||
|
||||
iter_header(testfile, None, rdr, &mut |ln| {
|
||||
// we should check if any only-<platform> exists and if it exists
|
||||
|
@ -101,6 +102,10 @@ impl EarlyProps {
|
|||
props.ignore = true;
|
||||
}
|
||||
|
||||
if !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress") {
|
||||
props.ignore = true;
|
||||
}
|
||||
|
||||
if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
|
||||
props.ignore = true;
|
||||
}
|
||||
|
|
|
@ -110,6 +110,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
|
|||
"x86_64-unknown-linux-gnu",
|
||||
];
|
||||
|
||||
pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
|
||||
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
|
||||
|
||||
const BIG_ENDIAN: &[&str] = &[
|
||||
"aarch64_be",
|
||||
"armebv7r",
|
||||
|
|
Loading…
Add table
Reference in a new issue