summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp6
-rw-r--r--compiler-rt/lib/hwasan/hwasan.cc118
-rw-r--r--compiler-rt/lib/hwasan/hwasan_interface_internal.h26
-rw-r--r--compiler-rt/lib/hwasan/hwasan_linux.cc8
-rw-r--r--compiler-rt/test/hwasan/TestCases/halt-on-error.cc38
-rw-r--r--llvm/include/llvm/Transforms/Instrumentation.h2
-rw-r--r--llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp25
-rw-r--r--llvm/test/Instrumentation/HWAddressSanitizer/basic.ll72
-rw-r--r--llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll39
9 files changed, 252 insertions, 82 deletions
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 2c033e0f7c0..e2349da5f0a 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -239,7 +239,11 @@ static void addKernelAddressSanitizerPasses(const PassManagerBuilder &Builder,
static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
- PM.add(createHWAddressSanitizerPass());
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper &>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::HWAddress);
+ PM.add(createHWAddressSanitizerPass(Recover));
}
static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
diff --git a/compiler-rt/lib/hwasan/hwasan.cc b/compiler-rt/lib/hwasan/hwasan.cc
index fcc40eb9018..8b1e5a7846a 100644
--- a/compiler-rt/lib/hwasan/hwasan.cc
+++ b/compiler-rt/lib/hwasan/hwasan.cc
@@ -252,40 +252,112 @@ static void SigIll() {
// __builtin_unreachable();
}
-template<bool IsStore, unsigned LogSize>
-__attribute__((always_inline, nodebug))
-static void CheckAddress(uptr p) {
+enum class ErrorAction { Abort, Recover };
+enum class AccessType { Load, Store };
+
+template <ErrorAction EA, AccessType AT, unsigned LogSize>
+__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
tag_t ptr_tag = GetTagFromPointer(p);
uptr ptr_raw = p & ~kAddressTagMask;
tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw);
- if (UNLIKELY(ptr_tag != mem_tag)) SigIll<0x100 + 0x10 * IsStore + LogSize>();
+ if (UNLIKELY(ptr_tag != mem_tag)) {
+ SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) +
+ 0x10 * (AT == AccessType::Store) + LogSize>();
+ if (EA == ErrorAction::Abort) __builtin_unreachable();
+ }
}
-template<bool IsStore>
-__attribute__((always_inline, nodebug))
-static void CheckAddressSized(uptr p, uptr sz) {
+template <ErrorAction EA, AccessType AT>
+__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
+ uptr sz) {
CHECK_NE(0, sz);
tag_t ptr_tag = GetTagFromPointer(p);
uptr ptr_raw = p & ~kAddressTagMask;
tag_t *shadow_first = (tag_t *)MEM_TO_SHADOW(ptr_raw);
tag_t *shadow_last = (tag_t *)MEM_TO_SHADOW(ptr_raw + sz - 1);
for (tag_t *t = shadow_first; t <= shadow_last; ++t)
- if (UNLIKELY(ptr_tag != *t)) SigIll<0x100 + 0x10 * IsStore + 0xf>();
-}
-
-void __hwasan_load(uptr p, uptr sz) { CheckAddressSized<false>(p, sz); }
-void __hwasan_load1(uptr p) { CheckAddress<false, 0>(p); }
-void __hwasan_load2(uptr p) { CheckAddress<false, 1>(p); }
-void __hwasan_load4(uptr p) { CheckAddress<false, 2>(p); }
-void __hwasan_load8(uptr p) { CheckAddress<false, 3>(p); }
-void __hwasan_load16(uptr p) { CheckAddress<false, 4>(p); }
-
-void __hwasan_store(uptr p, uptr sz) { CheckAddressSized<true>(p, sz); }
-void __hwasan_store1(uptr p) { CheckAddress<true, 0>(p); }
-void __hwasan_store2(uptr p) { CheckAddress<true, 1>(p); }
-void __hwasan_store4(uptr p) { CheckAddress<true, 2>(p); }
-void __hwasan_store8(uptr p) { CheckAddress<true, 3>(p); }
-void __hwasan_store16(uptr p) { CheckAddress<true, 4>(p); }
+ if (UNLIKELY(ptr_tag != *t)) {
+ SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) +
+ 0x10 * (AT == AccessType::Store) + 0xf>();
+ if (EA == ErrorAction::Abort) __builtin_unreachable();
+ }
+}
+
+void __hwasan_load(uptr p, uptr sz) {
+ CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz);
+}
+void __hwasan_load1(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Load, 0>(p);
+}
+void __hwasan_load2(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Load, 1>(p);
+}
+void __hwasan_load4(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Load, 2>(p);
+}
+void __hwasan_load8(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Load, 3>(p);
+}
+void __hwasan_load16(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Load, 4>(p);
+}
+
+void __hwasan_load_noabort(uptr p, uptr sz) {
+ CheckAddressSized<ErrorAction::Recover, AccessType::Load>(p, sz);
+}
+void __hwasan_load1_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Load, 0>(p);
+}
+void __hwasan_load2_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Load, 1>(p);
+}
+void __hwasan_load4_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Load, 2>(p);
+}
+void __hwasan_load8_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Load, 3>(p);
+}
+void __hwasan_load16_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Load, 4>(p);
+}
+
+void __hwasan_store(uptr p, uptr sz) {
+ CheckAddressSized<ErrorAction::Abort, AccessType::Store>(p, sz);
+}
+void __hwasan_store1(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Store, 0>(p);
+}
+void __hwasan_store2(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Store, 1>(p);
+}
+void __hwasan_store4(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Store, 2>(p);
+}
+void __hwasan_store8(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Store, 3>(p);
+}
+void __hwasan_store16(uptr p) {
+ CheckAddress<ErrorAction::Abort, AccessType::Store, 4>(p);
+}
+
+void __hwasan_store_noabort(uptr p, uptr sz) {
+ CheckAddressSized<ErrorAction::Recover, AccessType::Store>(p, sz);
+}
+void __hwasan_store1_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Store, 0>(p);
+}
+void __hwasan_store2_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Store, 1>(p);
+}
+void __hwasan_store4_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Store, 2>(p);
+}
+void __hwasan_store8_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Store, 3>(p);
+}
+void __hwasan_store16_noabort(uptr p) {
+ CheckAddress<ErrorAction::Recover, AccessType::Store, 4>(p);
+}
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h
index 08b77534e0a..7e95271ac0a 100644
--- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h
+++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h
@@ -45,6 +45,19 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_load16(uptr);
SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_load_noabort(uptr, uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_load1_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_load2_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_load4_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_load8_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_load16_noabort(uptr);
+
+SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_store(uptr, uptr);
SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_store1(uptr);
@@ -57,6 +70,19 @@ void __hwasan_store8(uptr);
SANITIZER_INTERFACE_ATTRIBUTE
void __hwasan_store16(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_store_noabort(uptr, uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_store1_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_store2_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_store4_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_store8_noabort(uptr);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_store16_noabort(uptr);
+
// Returns the offset of the first tag mismatch or -1 if the whole range is
// good.
SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cc b/compiler-rt/lib/hwasan/hwasan_linux.cc
index 264046960d8..48dea8eb6ff 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cc
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cc
@@ -174,12 +174,14 @@ struct AccessInfo {
uptr size;
bool is_store;
bool is_load;
+ bool recover;
};
#if defined(__aarch64__)
static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {
// Access type is encoded in HLT immediate as 0x1XY,
- // where X is 1 for store, 0 for load.
+ // where X&1 is 1 for store, 0 for load,
+ // and X&2 is 1 if the error is recoverable.
// Valid values of Y are 0 to 4, which are interpreted as log2(access_size),
// and 0xF, which means that access size is stored in X1 register.
// Access address is always in X0 register.
@@ -189,6 +191,7 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {
if ((code & 0xff00) != 0x100)
return AccessInfo{0, 0, false, false}; // Not ours.
bool is_store = code & 0x10;
+ bool recover = code & 0x20;
unsigned size_log = code & 0xf;
if (size_log > 4 && size_log != 0xf)
return AccessInfo{0, 0, false, false}; // Not ours.
@@ -200,6 +203,7 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {
ai.size = uc->uc_mcontext.regs[1];
else
ai.size = 1U << size_log;
+ ai.recover = recover;
return ai;
}
#else
@@ -223,7 +227,7 @@ static bool HwasanOnSIGILL(int signo, siginfo_t *info, ucontext_t *uc) {
ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store);
++hwasan_report_count;
- if (flags()->halt_on_error)
+ if (flags()->halt_on_error || !ai.recover)
Die();
uc->uc_mcontext.pc += 4;
diff --git a/compiler-rt/test/hwasan/TestCases/halt-on-error.cc b/compiler-rt/test/hwasan/TestCases/halt-on-error.cc
index 7c3cc5c68ca..fdf6d27d793 100644
--- a/compiler-rt/test/hwasan/TestCases/halt-on-error.cc
+++ b/compiler-rt/test/hwasan/TestCases/halt-on-error.cc
@@ -1,4 +1,19 @@
-// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON
+// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+
+// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON,RECOVER
+
+// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+
+// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
+// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON,RECOVER
+
// REQUIRES: stable-runtime
#include <stdlib.h>
@@ -10,17 +25,18 @@ int main() {
free(x);
__hwasan_disable_allocator_tagging();
return x[2] + ((char *)x)[6] + ((char *)x)[9];
- // CHECK: READ of size 4 at
- // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12
- // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main
+ // COMMON: READ of size 4 at
+ // When instrumenting with callbacks, main is actually #1, and #0 is __hwasan_load4.
+ // COMMON: #{{.*}} in main {{.*}}halt-on-error.cc:27
+ // COMMON: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in
- // CHECK: READ of size 1 at
- // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12
- // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main
+ // RECOVER: READ of size 1 at
+ // RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27
+ // RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in
- // CHECK: READ of size 1 at
- // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12
- // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main
+ // RECOVER: READ of size 1 at
+ // RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27
+ // RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in
- // CHECK-NOT: tag-mismatch
+ // COMMON-NOT: tag-mismatch
}
diff --git a/llvm/include/llvm/Transforms/Instrumentation.h b/llvm/include/llvm/Transforms/Instrumentation.h
index cd6b770f76a..b1e13f17aef 100644
--- a/llvm/include/llvm/Transforms/Instrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation.h
@@ -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();
diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index 2a25423e04b..8e2833d2203 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -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);
}
diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/basic.ll b/llvm/test/Instrumentation/HWAddressSanitizer/basic.ll
index db1f52fc56e..a5e49062669 100644
--- a/llvm/test/Instrumentation/HWAddressSanitizer/basic.ll
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/basic.ll
@@ -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
diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll b/llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll
index be3b33d4f8d..0a1713b8391 100644
--- a/llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll
@@ -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
OpenPOWER on IntegriCloud