Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -239,7 +239,11 @@ static void addHWAddressSanitizerPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createHWAddressSanitizerPass()); + const PassManagerBuilderWrapper &BuilderWrapper = + static_cast(Builder); + const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); + bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::HWAddress); + PM.add(createHWAddressSanitizerPass(Recover)); } static void addMemorySanitizerPass(const PassManagerBuilder &Builder, Index: compiler-rt/lib/hwasan/hwasan.cc =================================================================== --- compiler-rt/lib/hwasan/hwasan.cc +++ compiler-rt/lib/hwasan/hwasan.cc @@ -252,40 +252,112 @@ // __builtin_unreachable(); } -template -__attribute__((always_inline, nodebug)) -static void CheckAddress(uptr p) { +enum class ErrorAction { Abort, Recover }; +enum class AccessType { Load, Store }; + +template +__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 -__attribute__((always_inline, nodebug)) -static void CheckAddressSized(uptr p, uptr sz) { +template +__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(p, sz); } -void __hwasan_load1(uptr p) { CheckAddress(p); } -void __hwasan_load2(uptr p) { CheckAddress(p); } -void __hwasan_load4(uptr p) { CheckAddress(p); } -void __hwasan_load8(uptr p) { CheckAddress(p); } -void __hwasan_load16(uptr p) { CheckAddress(p); } - -void __hwasan_store(uptr p, uptr sz) { CheckAddressSized(p, sz); } -void __hwasan_store1(uptr p) { CheckAddress(p); } -void __hwasan_store2(uptr p) { CheckAddress(p); } -void __hwasan_store4(uptr p) { CheckAddress(p); } -void __hwasan_store8(uptr p) { CheckAddress(p); } -void __hwasan_store16(uptr p) { CheckAddress(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(p, sz); +} +void __hwasan_load1(uptr p) { + CheckAddress(p); +} +void __hwasan_load2(uptr p) { + CheckAddress(p); +} +void __hwasan_load4(uptr p) { + CheckAddress(p); +} +void __hwasan_load8(uptr p) { + CheckAddress(p); +} +void __hwasan_load16(uptr p) { + CheckAddress(p); +} + +void __hwasan_load_noabort(uptr p, uptr sz) { + CheckAddressSized(p, sz); +} +void __hwasan_load1_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_load2_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_load4_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_load8_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_load16_noabort(uptr p) { + CheckAddress(p); +} + +void __hwasan_store(uptr p, uptr sz) { + CheckAddressSized(p, sz); +} +void __hwasan_store1(uptr p) { + CheckAddress(p); +} +void __hwasan_store2(uptr p) { + CheckAddress(p); +} +void __hwasan_store4(uptr p) { + CheckAddress(p); +} +void __hwasan_store8(uptr p) { + CheckAddress(p); +} +void __hwasan_store16(uptr p) { + CheckAddress(p); +} + +void __hwasan_store_noabort(uptr p, uptr sz) { + CheckAddressSized(p, sz); +} +void __hwasan_store1_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_store2_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_store4_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_store8_noabort(uptr p) { + CheckAddress(p); +} +void __hwasan_store16_noabort(uptr p) { + CheckAddress(p); +} #if !SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { Index: compiler-rt/lib/hwasan/hwasan_interface_internal.h =================================================================== --- compiler-rt/lib/hwasan/hwasan_interface_internal.h +++ compiler-rt/lib/hwasan/hwasan_interface_internal.h @@ -44,6 +44,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 @@ -57,6 +70,19 @@ 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 Index: compiler-rt/lib/hwasan/hwasan_linux.cc =================================================================== --- compiler-rt/lib/hwasan/hwasan_linux.cc +++ compiler-rt/lib/hwasan/hwasan_linux.cc @@ -174,12 +174,14 @@ 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 @@ 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 @@ ai.size = uc->uc_mcontext.regs[1]; else ai.size = 1U << size_log; + ai.recover = recover; return ai; } #else @@ -223,7 +227,7 @@ 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; Index: compiler-rt/test/hwasan/TestCases/halt-on-error.cc =================================================================== --- compiler-rt/test/hwasan/TestCases/halt-on-error.cc +++ compiler-rt/test/hwasan/TestCases/halt-on-error.cc @@ -1,4 +1,19 @@ +// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK // RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK + +// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK +// 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=CHECK +// 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-prefix=CHECK-RECOVER + +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK +// 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=CHECK +// 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=CHECK + +// 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=CHECK +// 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=CHECK +// 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-prefix=CHECK-RECOVER + // REQUIRES: stable-runtime #include @@ -11,16 +26,17 @@ __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 + // When instrumenting with callbacks, main is actually #1, and #0 is __hwasan_load4. + // CHECK: #{{.*}} in main {{.*}}halt-on-error.cc:27 + // CHECK: 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 + // CHECK-RECOVER: READ of size 1 at + // CHECK-RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27 + // CHECK-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 + // CHECK-RECOVER: READ of size 1 at + // CHECK-RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27 + // CHECK-RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in // CHECK-NOT: tag-mismatch } Index: llvm/include/llvm/Transforms/Instrumentation.h =================================================================== --- llvm/include/llvm/Transforms/Instrumentation.h +++ llvm/include/llvm/Transforms/Instrumentation.h @@ -133,7 +133,7 @@ FunctionPass *createMemorySanitizerPass(int TrackOrigins = 0, bool Recover = false); -FunctionPass *createHWAddressSanitizerPass(); +FunctionPass *createHWAddressSanitizerPass(bool Recover = false); // Insert ThreadSanitizer (race detection) instrumentation FunctionPass *createThreadSanitizerPass(); Index: llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -80,6 +80,11 @@ cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, cl::init(true)); +static cl::opt 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 @@ // 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 @@ LLVMContext *C; Type *IntptrTy; + bool Recover; + Function *HwasanCtorFunction; Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes]; @@ -126,8 +134,8 @@ 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 @@ 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 @@ 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 @@ 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); } Index: llvm/test/Instrumentation/HWAddressSanitizer/basic.ll =================================================================== --- llvm/test/Instrumentation/HWAddressSanitizer/basic.ll +++ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 @@ 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 Index: llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll =================================================================== --- llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll +++ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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