Skip to content

Commit c7d9bff

Browse files
author
Tri Vo
committed
HWASan support
1 parent 0b7a598 commit c7d9bff

File tree

18 files changed

+100
-12
lines changed

18 files changed

+100
-12
lines changed

Diff for: compiler/rustc_codegen_llvm/src/attributes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V
5353
if enabled.contains(SanitizerSet::THREAD) {
5454
llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
5555
}
56+
if enabled.contains(SanitizerSet::HWADDRESS) {
57+
llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
58+
}
5659
}
5760

5861
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.

Diff for: compiler/rustc_codegen_llvm/src/back/write.rs

+6
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
440440
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
441441
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
442442
sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
443+
sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
444+
sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),
443445
})
444446
} else {
445447
None
@@ -652,6 +654,10 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
652654
if config.sanitizer.contains(SanitizerSet::THREAD) {
653655
passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
654656
}
657+
if config.sanitizer.contains(SanitizerSet::HWADDRESS) {
658+
let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS);
659+
passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover));
660+
}
655661
}
656662

657663
pub(crate) fn link(

Diff for: compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+4
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ pub enum Attribute {
131131
ReturnsTwice = 25,
132132
ReadNone = 26,
133133
InaccessibleMemOnly = 27,
134+
SanitizeHWAddress = 28,
134135
}
135136

136137
/// LLVMIntPredicate
@@ -439,6 +440,8 @@ pub struct SanitizerOptions {
439440
pub sanitize_memory_recover: bool,
440441
pub sanitize_memory_track_origins: c_int,
441442
pub sanitize_thread: bool,
443+
pub sanitize_hwaddress: bool,
444+
pub sanitize_hwaddress_recover: bool,
442445
}
443446

444447
/// LLVMRelocMode
@@ -2128,6 +2131,7 @@ extern "C" {
21282131
Recover: bool,
21292132
) -> &'static mut Pass;
21302133
pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass;
2134+
pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
21312135
pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
21322136
pub fn LLVMRustAddLastExtensionPasses(
21332137
PMB: &PassManagerBuilder,

Diff for: compiler/rustc_codegen_ssa/src/back/link.rs

+3
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
893893
if sanitizer.contains(SanitizerSet::THREAD) {
894894
link_sanitizer_runtime(sess, linker, "tsan");
895895
}
896+
if sanitizer.contains(SanitizerSet::HWADDRESS) {
897+
link_sanitizer_runtime(sess, linker, "hwasan");
898+
}
896899
}
897900

898901
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {

Diff for: compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
8585
ReturnsTwice = 25,
8686
ReadNone = 26,
8787
InaccessibleMemOnly = 27,
88+
SanitizeHWAddress = 28,
8889
};
8990

9091
typedef struct OpaqueRustString *RustStringRef;

Diff for: compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "llvm/Support/TimeProfiler.h"
3434
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
3535
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
36+
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
3637
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
3738
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
3839

@@ -133,6 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
133134
return wrap(createThreadSanitizerLegacyPassPass());
134135
}
135136

137+
extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
138+
const bool CompileKernel = false;
139+
140+
return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
141+
}
142+
136143
extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
137144
assert(RustPass);
138145
Pass *Pass = unwrap(RustPass);
@@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions {
722729
bool SanitizeMemoryRecover;
723730
int SanitizeMemoryTrackOrigins;
724731
bool SanitizeThread;
732+
bool SanitizeHWAddress;
733+
bool SanitizeHWAddressRecover;
725734
};
726735

727736
extern "C" void
@@ -886,6 +895,23 @@ LLVMRustOptimizeWithNewPassManager(
886895
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
887896
}
888897
);
898+
#endif
899+
}
900+
if (SanitizerOptions->SanitizeHWAddress) {
901+
#if LLVM_VERSION_GE(11, 0)
902+
OptimizerLastEPCallbacks.push_back(
903+
[SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
904+
MPM.addPass(HWAddressSanitizerPass(
905+
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
906+
}
907+
);
908+
#else
909+
PipelineStartEPCallbacks.push_back(
910+
[SanitizerOptions](ModulePassManager &MPM) {
911+
MPM.addPass(HWAddressSanitizerPass(
912+
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
913+
}
914+
);
889915
#endif
890916
}
891917
}

Diff for: compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
205205
return Attribute::ReadNone;
206206
case InaccessibleMemOnly:
207207
return Attribute::InaccessibleMemOnly;
208+
case SanitizeHWAddress:
209+
return Attribute::SanitizeHWAddress;
208210
}
209211
report_fatal_error("bad AttributeKind");
210212
}

Diff for: compiler/rustc_session/src/config.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ bitflags! {
4343
const LEAK = 1 << 1;
4444
const MEMORY = 1 << 2;
4545
const THREAD = 1 << 3;
46+
const HWADDRESS = 1 << 4;
4647
}
4748
}
4849

@@ -56,6 +57,7 @@ impl fmt::Display for SanitizerSet {
5657
SanitizerSet::LEAK => "leak",
5758
SanitizerSet::MEMORY => "memory",
5859
SanitizerSet::THREAD => "thread",
60+
SanitizerSet::HWADDRESS => "hwaddress",
5961
_ => panic!("unrecognized sanitizer {:?}", s),
6062
};
6163
if !first {
@@ -73,12 +75,18 @@ impl IntoIterator for SanitizerSet {
7375
type IntoIter = std::vec::IntoIter<SanitizerSet>;
7476

7577
fn into_iter(self) -> Self::IntoIter {
76-
[SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
77-
.iter()
78-
.copied()
79-
.filter(|&s| self.contains(s))
80-
.collect::<Vec<_>>()
81-
.into_iter()
78+
[
79+
SanitizerSet::ADDRESS,
80+
SanitizerSet::LEAK,
81+
SanitizerSet::MEMORY,
82+
SanitizerSet::THREAD,
83+
SanitizerSet::HWADDRESS,
84+
]
85+
.iter()
86+
.copied()
87+
.filter(|&s| self.contains(s))
88+
.collect::<Vec<_>>()
89+
.into_iter()
8290
}
8391
}
8492

Diff for: compiler/rustc_session/src/options.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ macro_rules! options {
253253
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
254254
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
255255
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
256-
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
256+
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
257257
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
258258
pub const parse_cfguard: &str =
259259
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -476,6 +476,7 @@ macro_rules! options {
476476
"leak" => SanitizerSet::LEAK,
477477
"memory" => SanitizerSet::MEMORY,
478478
"thread" => SanitizerSet::THREAD,
479+
"hwaddress" => SanitizerSet::HWADDRESS,
479480
_ => return false,
480481
}
481482
}

Diff for: compiler/rustc_session/src/session.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,8 @@ impl Session {
11261126
self.opts.optimize != config::OptLevel::No
11271127
// AddressSanitizer uses lifetimes to detect use after scope bugs.
11281128
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
1129-
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
1129+
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
1130+
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
11301131
}
11311132

11321133
pub fn link_dead_code(&self) -> bool {
@@ -1562,6 +1563,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
15621563
"x86_64-unknown-freebsd",
15631564
"x86_64-unknown-linux-gnu",
15641565
];
1566+
const HWASAN_SUPPORTED_TARGETS: &[&str] =
1567+
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
15651568

15661569
// Sanitizers can only be used on some tested platforms.
15671570
for s in sess.opts.debugging_opts.sanitizer {
@@ -1570,6 +1573,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
15701573
SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
15711574
SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
15721575
SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
1576+
SanitizerSet::HWADDRESS => HWASAN_SUPPORTED_TARGETS,
15731577
_ => panic!("unrecognized sanitizer {}", s),
15741578
};
15751579
if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {

Diff for: compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ symbols! {
593593
html_no_source,
594594
html_playground_url,
595595
html_root_url,
596+
hwaddress,
596597
i,
597598
i128,
598599
i128_type,

Diff for: compiler/rustc_typeck/src/collect.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2628,10 +2628,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
26282628
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
26292629
} else if item.has_name(sym::thread) {
26302630
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
2631+
} else if item.has_name(sym::hwaddress) {
2632+
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
26312633
} else {
26322634
tcx.sess
26332635
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
2634-
.note("expected one of: `address`, `memory` or `thread`")
2636+
.note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
26352637
.emit();
26362638
}
26372639
}

Diff for: src/bootstrap/configure.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def v(*args):
5151
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
5252
o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
5353
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
54-
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)")
54+
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
5555
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
5656
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
5757
o("profiler", "build.profiler", "build the profiler runtime")

Diff for: src/bootstrap/native.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ fn supported_sanitizers(
804804
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
805805
"aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
806806
"aarch64-unknown-linux-gnu" => {
807-
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"])
807+
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
808808
}
809809
"x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
810810
"x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),

Diff for: src/test/ui/invalid/invalid-no-sanitize.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize`
44
LL | #[no_sanitize(brontosaurus)]
55
| ^^^^^^^^^^^^
66
|
7-
= note: expected one of: `address`, `memory` or `thread`
7+
= note: expected one of: `address`, `hwaddress`, `memory` or `thread`
88

99
error: aborting due to previous error
1010

Diff for: src/test/ui/sanitize/hwaddress.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// needs-sanitizer-support
2+
// needs-sanitizer-hwaddress
3+
//
4+
// compile-flags: -Z sanitizer=hwaddress -O -g
5+
//
6+
// run-fail
7+
// error-pattern: HWAddressSanitizer: tag-mismatch
8+
9+
#![feature(test)]
10+
11+
use std::hint::black_box;
12+
13+
fn main() {
14+
let xs = vec![0, 1, 2, 3];
15+
// Avoid optimizing everything out.
16+
let xs = black_box(xs.as_ptr());
17+
let code = unsafe { *xs.offset(4) };
18+
std::process::exit(code);
19+
}

Diff for: src/tools/compiletest/src/header.rs

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl EarlyProps {
4848
let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
4949
let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
5050
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
51+
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
5152

5253
iter_header(testfile, None, rdr, &mut |ln| {
5354
// we should check if any only-<platform> exists and if it exists
@@ -101,6 +102,10 @@ impl EarlyProps {
101102
props.ignore = true;
102103
}
103104

105+
if !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress") {
106+
props.ignore = true;
107+
}
108+
104109
if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
105110
props.ignore = true;
106111
}

Diff for: src/tools/compiletest/src/util.rs

+3
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
110110
"x86_64-unknown-linux-gnu",
111111
];
112112

113+
pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
114+
&["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
115+
113116
const BIG_ENDIAN: &[&str] = &[
114117
"aarch64_be",
115118
"armebv7r",

0 commit comments

Comments
 (0)