1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

[hwasan] Implement -fsanitize-recover=hwaddress.

Summary: Very similar to AddressSanitizer, with the exception of the error type encoding.

Reviewers: kcc, alekseyshl

Subscribers: cfe-commits, kubamracek, llvm-commits, hiraditya

Differential Revision: https://reviews.llvm.org/D41417

llvm-svn: 321203
This commit is contained in:
Evgeniy Stepanov 2017-12-20 19:05:44 +00:00
parent c6e25cd04d
commit 552fbc5607
4 changed files with 93 additions and 45 deletions

View File

@ -133,7 +133,7 @@ ModulePass *createAddressSanitizerModulePass(bool CompileKernel = false,
FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0,
bool Recover = false);
FunctionPass *createHWAddressSanitizerPass();
FunctionPass *createHWAddressSanitizerPass(bool Recover = false);
// Insert ThreadSanitizer (race detection) instrumentation
FunctionPass *createThreadSanitizerPass();

View File

@ -80,6 +80,11 @@ static cl::opt<bool> ClInstrumentAtomics(
cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
cl::init(true));
static cl::opt<bool> ClRecover(
"hwasan-recover",
cl::desc("Enable recovery mode (continue-after-error)."),
cl::Hidden, cl::init(false));
namespace {
/// \brief An instrumentation pass implementing detection of addressability bugs
@ -89,7 +94,8 @@ public:
// Pass identification, replacement for typeid.
static char ID;
HWAddressSanitizer() : FunctionPass(ID) {}
HWAddressSanitizer(bool Recover = false)
: FunctionPass(ID), Recover(Recover || ClRecover) {}
StringRef getPassName() const override { return "HWAddressSanitizer"; }
@ -109,6 +115,8 @@ private:
LLVMContext *C;
Type *IntptrTy;
bool Recover;
Function *HwasanCtorFunction;
Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
@ -126,8 +134,8 @@ INITIALIZE_PASS_END(
HWAddressSanitizer, "hwasan",
"HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
FunctionPass *llvm::createHWAddressSanitizerPass() {
return new HWAddressSanitizer();
FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) {
return new HWAddressSanitizer(Recover);
}
/// \brief Module-level initialization.
@ -156,10 +164,11 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) {
IRBuilder<> IRB(*C);
for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
const std::string TypeStr = AccessIsWrite ? "store" : "load";
const std::string EndingStr = Recover ? "_noabort" : "";
HwasanMemoryAccessCallbackSized[AccessIsWrite] =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
ClMemoryAccessCallbackPrefix + TypeStr,
ClMemoryAccessCallbackPrefix + TypeStr + EndingStr,
FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
@ -167,7 +176,7 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) {
HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
checkSanitizerInterfaceFunction(M.getOrInsertFunction(
ClMemoryAccessCallbackPrefix + TypeStr +
itostr(1ULL << AccessSizeIndex),
itostr(1ULL << AccessSizeIndex) + EndingStr,
FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
}
}
@ -246,14 +255,16 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
TerminatorInst *CheckTerm =
SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, false,
SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
MDBuilder(*C).createBranchWeights(1, 100000));
IRB.SetInsertPoint(CheckTerm);
// The signal handler will find the data address in x0.
InlineAsm *Asm = InlineAsm::get(
FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
"hlt #" + itostr(0x100 + IsWrite * 0x10 + AccessSizeIndex), "{x0}",
"hlt #" +
itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex),
"{x0}",
/*hasSideEffects=*/true);
IRB.CreateCall(Asm, PtrLong);
}

View File

@ -1,6 +1,7 @@
; Test basic address sanitizer instrumentation.
;
; RUN: opt < %s -hwasan -S | FileCheck %s
; RUN: opt < %s -hwasan -hwasan-recover=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT
; RUN: opt < %s -hwasan -hwasan-recover=1 -S | FileCheck %s --check-prefixes=CHECK,RECOVER
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--linux-android"
@ -17,8 +18,10 @@ define i8 @test_load8(i8* %a) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #256", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #256", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #288", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: %[[G:[^ ]*]] = load i8, i8* %a, align 4
; CHECK: ret i8 %[[G]]
@ -40,8 +43,10 @@ define i16 @test_load16(i16* %a) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #257", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #257", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #289", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: %[[G:[^ ]*]] = load i16, i16* %a, align 4
; CHECK: ret i16 %[[G]]
@ -63,8 +68,10 @@ define i32 @test_load32(i32* %a) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #258", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #258", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #290", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: %[[G:[^ ]*]] = load i32, i32* %a, align 4
; CHECK: ret i32 %[[G]]
@ -86,8 +93,10 @@ define i64 @test_load64(i64* %a) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #259", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #259", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #291", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: %[[G:[^ ]*]] = load i64, i64* %a, align 8
; CHECK: ret i64 %[[G]]
@ -109,8 +118,10 @@ define i128 @test_load128(i128* %a) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #260", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #260", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #292", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: %[[G:[^ ]*]] = load i128, i128* %a, align 16
; CHECK: ret i128 %[[G]]
@ -123,7 +134,8 @@ entry:
define i40 @test_load40(i40* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load40(
; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
; CHECK: call void @__hwasan_load(i64 %[[A]], i64 5)
; ABORT: call void @__hwasan_load(i64 %[[A]], i64 5)
; RECOVER: call void @__hwasan_load_noabort(i64 %[[A]], i64 5)
; CHECK: %[[B:[^ ]*]] = load i40, i40* %a
; CHECK: ret i40 %[[B]]
@ -144,8 +156,10 @@ define void @test_store8(i8* %a, i8 %b) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #272", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #272", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #304", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: store i8 %b, i8* %a, align 4
; CHECK: ret void
@ -167,8 +181,10 @@ define void @test_store16(i16* %a, i16 %b) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #273", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #273", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #305", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: store i16 %b, i16* %a, align 4
; CHECK: ret void
@ -190,8 +206,10 @@ define void @test_store32(i32* %a, i32 %b) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #274", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #274", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #306", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: store i32 %b, i32* %a, align 4
; CHECK: ret void
@ -213,8 +231,10 @@ define void @test_store64(i64* %a, i64 %b) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #275", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #275", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #307", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: store i64 %b, i64* %a, align 8
; CHECK: ret void
@ -236,8 +256,10 @@ define void @test_store128(i128* %a, i128 %b) sanitize_hwaddress {
; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
; CHECK: call void asm sideeffect "hlt #276", "{x0}"(i64 %[[A]])
; CHECK: br label
; ABORT: call void asm sideeffect "hlt #276", "{x0}"(i64 %[[A]])
; ABORT: unreachable
; RECOVER: call void asm sideeffect "hlt #308", "{x0}"(i64 %[[A]])
; RECOVER: br label
; CHECK: store i128 %b, i128* %a, align 16
; CHECK: ret void
@ -250,7 +272,8 @@ entry:
define void @test_store40(i40* %a, i40 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store40(
; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
; CHECK: call void @__hwasan_store(i64 %[[A]], i64 5)
; ABORT: call void @__hwasan_store(i64 %[[A]], i64 5)
; RECOVER: call void @__hwasan_store_noabort(i64 %[[A]], i64 5)
; CHECK: store i40 %b, i40* %a
; CHECK: ret void
@ -262,7 +285,8 @@ entry:
define void @test_store_unaligned(i64* %a, i64 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store_unaligned(
; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
; CHECK: call void @__hwasan_store(i64 %[[A]], i64 8)
; ABORT: call void @__hwasan_store(i64 %[[A]], i64 8)
; RECOVER: call void @__hwasan_store_noabort(i64 %[[A]], i64 8)
; CHECK: store i64 %b, i64* %a, align 4
; CHECK: ret void

View File

@ -1,6 +1,7 @@
; Test basic address sanitizer instrumentation.
;
; RUN: opt < %s -hwasan -hwasan-instrument-with-calls -S | FileCheck %s
; RUN: opt < %s -hwasan -hwasan-instrument-with-calls -S | FileCheck %s --check-prefixes=CHECK,ABORT
; RUN: opt < %s -hwasan -hwasan-instrument-with-calls -hwasan-recover=1 -S | FileCheck %s --check-prefixes=CHECK,RECOVER
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--linux-android"
@ -8,7 +9,8 @@ target triple = "aarch64--linux-android"
define i8 @test_load8(i8* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load8(
; CHECK: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
; CHECK: call void @__hwasan_load1(i64 %[[A]])
; ABORT: call void @__hwasan_load1(i64 %[[A]])
; RECOVER: call void @__hwasan_load1_noabort(i64 %[[A]])
; CHECK: %[[B:[^ ]*]] = load i8, i8* %a
; CHECK: ret i8 %[[B]]
@ -20,7 +22,8 @@ entry:
define i16 @test_load16(i16* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load16(
; CHECK: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
; CHECK: call void @__hwasan_load2(i64 %[[A]])
; ABORT: call void @__hwasan_load2(i64 %[[A]])
; RECOVER: call void @__hwasan_load2_noabort(i64 %[[A]])
; CHECK: %[[B:[^ ]*]] = load i16, i16* %a
; CHECK: ret i16 %[[B]]
@ -32,7 +35,8 @@ entry:
define i32 @test_load32(i32* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load32(
; CHECK: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
; CHECK: call void @__hwasan_load4(i64 %[[A]])
; ABORT: call void @__hwasan_load4(i64 %[[A]])
; RECOVER: call void @__hwasan_load4_noabort(i64 %[[A]])
; CHECK: %[[B:[^ ]*]] = load i32, i32* %a
; CHECK: ret i32 %[[B]]
@ -44,7 +48,8 @@ entry:
define i64 @test_load64(i64* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load64(
; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
; CHECK: call void @__hwasan_load8(i64 %[[A]])
; ABORT: call void @__hwasan_load8(i64 %[[A]])
; RECOVER: call void @__hwasan_load8_noabort(i64 %[[A]])
; CHECK: %[[B:[^ ]*]] = load i64, i64* %a
; CHECK: ret i64 %[[B]]
@ -56,7 +61,8 @@ entry:
define i128 @test_load128(i128* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load128(
; CHECK: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
; CHECK: call void @__hwasan_load16(i64 %[[A]])
; ABORT: call void @__hwasan_load16(i64 %[[A]])
; RECOVER: call void @__hwasan_load16_noabort(i64 %[[A]])
; CHECK: %[[B:[^ ]*]] = load i128, i128* %a
; CHECK: ret i128 %[[B]]
@ -68,7 +74,8 @@ entry:
define i40 @test_load40(i40* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load40(
; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
; CHECK: call void @__hwasan_load(i64 %[[A]], i64 5)
; ABORT: call void @__hwasan_load(i64 %[[A]], i64 5)
; RECOVER: call void @__hwasan_load_noabort(i64 %[[A]], i64 5)
; CHECK: %[[B:[^ ]*]] = load i40, i40* %a
; CHECK: ret i40 %[[B]]
@ -80,7 +87,8 @@ entry:
define void @test_store8(i8* %a, i8 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store8(
; CHECK: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
; CHECK: call void @__hwasan_store1(i64 %[[A]])
; ABORT: call void @__hwasan_store1(i64 %[[A]])
; RECOVER: call void @__hwasan_store1_noabort(i64 %[[A]])
; CHECK: store i8 %b, i8* %a
; CHECK: ret void
@ -92,7 +100,8 @@ entry:
define void @test_store16(i16* %a, i16 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store16(
; CHECK: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
; CHECK: call void @__hwasan_store2(i64 %[[A]])
; ABORT: call void @__hwasan_store2(i64 %[[A]])
; RECOVER: call void @__hwasan_store2_noabort(i64 %[[A]])
; CHECK: store i16 %b, i16* %a
; CHECK: ret void
@ -104,7 +113,8 @@ entry:
define void @test_store32(i32* %a, i32 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store32(
; CHECK: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
; CHECK: call void @__hwasan_store4(i64 %[[A]])
; ABORT: call void @__hwasan_store4(i64 %[[A]])
; RECOVER: call void @__hwasan_store4_noabort(i64 %[[A]])
; CHECK: store i32 %b, i32* %a
; CHECK: ret void
@ -116,7 +126,8 @@ entry:
define void @test_store64(i64* %a, i64 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store64(
; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
; CHECK: call void @__hwasan_store8(i64 %[[A]])
; ABORT: call void @__hwasan_store8(i64 %[[A]])
; RECOVER: call void @__hwasan_store8_noabort(i64 %[[A]])
; CHECK: store i64 %b, i64* %a
; CHECK: ret void
@ -128,7 +139,8 @@ entry:
define void @test_store128(i128* %a, i128 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store128(
; CHECK: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
; CHECK: call void @__hwasan_store16(i64 %[[A]])
; ABORT: call void @__hwasan_store16(i64 %[[A]])
; RECOVER: call void @__hwasan_store16_noabort(i64 %[[A]])
; CHECK: store i128 %b, i128* %a
; CHECK: ret void
@ -140,7 +152,8 @@ entry:
define void @test_store40(i40* %a, i40 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store40(
; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
; CHECK: call void @__hwasan_store(i64 %[[A]], i64 5)
; ABORT: call void @__hwasan_store(i64 %[[A]], i64 5)
; RECOVER: call void @__hwasan_store_noabort(i64 %[[A]], i64 5)
; CHECK: store i40 %b, i40* %a
; CHECK: ret void