Index: llvm/trunk/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp =================================================================== --- llvm/trunk/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ llvm/trunk/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -52,11 +52,15 @@ static const char *const kHwasanModuleCtorName = "hwasan.module_ctor"; static const char *const kHwasanInitName = "__hwasan_init"; +static const char *const kHwasanShadowMemoryDynamicAddress = + "__hwasan_shadow_memory_dynamic_address"; + // Accesses sizes are powers of two: 1, 2, 4, 8, 16. static const size_t kNumberOfAccessSizes = 5; -static const size_t kShadowScale = 4; -static const unsigned kAllocaAlignment = 1U << kShadowScale; +static const size_t kDefaultShadowScale = 4; +static const uint64_t kDynamicShadowSentinel = + std::numeric_limits::max(); static const unsigned kPointerTagShift = 56; static cl::opt ClMemoryAccessCallbackPrefix( @@ -96,20 +100,25 @@ cl::desc("generate new tags with runtime library calls"), cl::Hidden, cl::init(false)); -static cl::opt ClMappingOffset( - "hwasan-mapping-offset", - cl::desc("offset of hwasan shadow mapping [EXPERIMENTAL]"), cl::Hidden, - cl::init(0)); - static cl::opt ClMatchAllTag( "hwasan-match-all-tag", - cl::desc("don't report bad accesses via pointers with this tag"), cl::Hidden, - cl::init(-1)); + cl::desc("don't report bad accesses via pointers with this tag"), + cl::Hidden, cl::init(-1)); static cl::opt ClEnableKhwasan( - "hwasan-kernel", cl::desc("Enable KernelHWAddressSanitizer instrumentation"), + "hwasan-kernel", + cl::desc("Enable KernelHWAddressSanitizer instrumentation"), cl::Hidden, cl::init(false)); +// These flags allow to change the shadow mapping and control how shadow memory +// is accessed. The shadow mapping looks like: +// Shadow = (Mem >> scale) + offset + +static cl::opt ClMappingOffset( + "hwasan-mapping-offset", + cl::desc("HWASan shadow mapping offset [EXPERIMENTAL]"), cl::Hidden, + cl::init(0)); + namespace { /// \brief An instrumentation pass implementing detection of addressability bugs @@ -132,7 +141,11 @@ bool doInitialization(Module &M) override; void initializeCallbacks(Module &M); + + void maybeInsertDynamicShadowAtFunctionEntry(Function &F); + void untagPointerOperand(Instruction *I, Value *Addr); + Value *memToShadow(Value *Shadow, Type *Ty, IRBuilder<> &IRB); void instrumentMemAccessInline(Value *PtrLong, bool IsWrite, unsigned AccessSizeIndex, Instruction *InsertBefore); @@ -157,6 +170,21 @@ LLVMContext *C; Triple TargetTriple; + /// This struct defines the shadow mapping using the rule: + /// shadow = (mem >> Scale) + Offset. + /// If InGlobal is true, then + /// extern char __hwasan_shadow[]; + /// shadow = (mem >> Scale) + &__hwasan_shadow + struct ShadowMapping { + int Scale; + uint64_t Offset; + bool InGlobal; + + void init(Triple &TargetTriple); + unsigned getAllocaAlignment() const { return 1U << Scale; } + }; + ShadowMapping Mapping; + Type *IntptrTy; Type *Int8Ty; @@ -170,6 +198,10 @@ Function *HwasanTagMemoryFunc; Function *HwasanGenerateTagFunc; + + Constant *ShadowGlobal; + + Value *LocalDynamicShadow = nullptr; }; } // end anonymous namespace @@ -178,10 +210,12 @@ INITIALIZE_PASS_BEGIN( HWAddressSanitizer, "hwasan", - "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) + "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, + false) INITIALIZE_PASS_END( HWAddressSanitizer, "hwasan", - "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) + "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, + false) FunctionPass *llvm::createHWAddressSanitizerPass(bool CompileKernel, bool Recover) { @@ -198,6 +232,8 @@ TargetTriple = Triple(M.getTargetTriple()); + Mapping.init(TargetTriple); + C = &(M.getContext()); IRBuilder<> IRB(*C); IntptrTy = IRB.getIntPtrTy(DL); @@ -240,6 +276,31 @@ "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy)); HwasanGenerateTagFunc = checkSanitizerInterfaceFunction( M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty)); + + if (Mapping.InGlobal) + ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow", + ArrayType::get(IRB.getInt8Ty(), 0)); +} + +void HWAddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) { + // Generate code only when dynamic addressing is needed. + if (Mapping.Offset != kDynamicShadowSentinel) + return; + + IRBuilder<> IRB(&F.front().front()); + if (Mapping.InGlobal) { + // An empty inline asm with input reg == output reg. + // An opaque pointer-to-int cast, basically. + InlineAsm *Asm = InlineAsm::get( + FunctionType::get(IntptrTy, {ShadowGlobal->getType()}, false), + StringRef(""), StringRef("=r,0"), + /*hasSideEffects=*/false); + LocalDynamicShadow = IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow"); + } else { + Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( + kHwasanShadowMemoryDynamicAddress, IntptrTy); + LocalDynamicShadow = IRB.CreateLoad(GlobalDynamicAddress); + } } Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I, @@ -250,6 +311,10 @@ // Skip memory accesses inserted by another instrumentation. if (I->getMetadata("nosanitize")) return nullptr; + // Do not instrument the load fetching the dynamic shadow address. + if (LocalDynamicShadow == I) + return nullptr; + Value *PtrOperand = nullptr; const DataLayout &DL = I->getModule()->getDataLayout(); if (LoadInst *LI = dyn_cast(I)) { @@ -279,7 +344,7 @@ } if (PtrOperand) { - // Do not instrument acesses from different address spaces; we cannot deal + // Do not instrument accesses from different address spaces; we cannot deal // with them. Type *PtrTy = cast(PtrOperand->getType()->getScalarType()); if (PtrTy->getPointerAddressSpace() != 0) @@ -326,6 +391,20 @@ I->setOperand(getPointerOperandIndex(I), UntaggedPtr); } +Value *HWAddressSanitizer::memToShadow(Value *Mem, Type *Ty, IRBuilder<> &IRB) { + // Mem >> Scale + Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale); + if (Mapping.Offset == 0) + return Shadow; + // (Mem >> Scale) + Offset + Value *ShadowBase; + if (LocalDynamicShadow) + ShadowBase = LocalDynamicShadow; + else + ShadowBase = ConstantInt::get(Ty, Mapping.Offset); + return IRB.CreateAdd(Shadow, ShadowBase); +} + void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite, unsigned AccessSizeIndex, Instruction *InsertBefore) { @@ -333,11 +412,7 @@ Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty()); Value *AddrLong = untagPointer(IRB, PtrLong); - Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale); - if (ClMappingOffset) - ShadowLong = IRB.CreateAdd( - ShadowLong, ConstantInt::get(PtrLong->getType(), ClMappingOffset, - /*isSigned=*/false)); + Value *ShadowLong = memToShadow(AddrLong, PtrLong->getType(), IRB); Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy())); Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag); @@ -400,7 +475,7 @@ Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); if (isPowerOf2_64(TypeSize) && (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) && - (Alignment >= (1UL << kShadowScale) || Alignment == 0 || + (Alignment >= (1UL << Mapping.Scale) || Alignment == 0 || Alignment >= TypeSize / 8)) { size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize); if (ClInstrumentWithCalls) { @@ -432,8 +507,8 @@ bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag) { - size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) & - ~(kAllocaAlignment - 1); + size_t Size = (getAllocaSizeInBytes(*AI) + Mapping.getAllocaAlignment() - 1) & + ~(Mapping.getAllocaAlignment() - 1); Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty()); if (ClInstrumentWithCalls) { @@ -441,9 +516,9 @@ {IRB.CreatePointerCast(AI, IntptrTy), JustTag, ConstantInt::get(IntptrTy, Size)}); } else { - size_t ShadowSize = Size >> kShadowScale; + size_t ShadowSize = Size >> Mapping.Scale; Value *ShadowPtr = IRB.CreateIntToPtr( - IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale), + memToShadow(IRB.CreatePointerCast(AI, IntptrTy), AI->getType(), IRB), IRB.getInt8PtrTy()); // If this memset is not inlined, it will be intercepted in the hwasan // runtime library. That's OK, because the interceptor skips the checks if @@ -508,8 +583,8 @@ } // Add a tag to an address. -Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, - Value *Tag) { +Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty, + Value *PtrLong, Value *Tag) { Value *TaggedPtrLong; if (CompileKernel) { // Kernel addresses have 0xFF in the most significant byte. @@ -613,6 +688,9 @@ initializeCallbacks(*F.getParent()); + assert(!LocalDynamicShadow); + maybeInsertDynamicShadowAtFunctionEntry(F); + bool Changed = false; SmallVector ToInstrument; SmallVector AllocasToInstrument; @@ -623,15 +701,16 @@ if (AllocaInst *AI = dyn_cast(&Inst)) { // Realign all allocas. We don't want small uninteresting allocas to // hide in instrumented alloca's padding. - if (AI->getAlignment() < kAllocaAlignment) - AI->setAlignment(kAllocaAlignment); + if (AI->getAlignment() < Mapping.getAllocaAlignment()) + AI->setAlignment(Mapping.getAllocaAlignment()); // Instrument some of them. if (isInterestingAlloca(*AI)) AllocasToInstrument.push_back(AI); continue; } - if (isa(Inst) || isa(Inst) || isa(Inst)) + if (isa(Inst) || isa(Inst) || + isa(Inst)) RetVec.push_back(&Inst); Value *MaybeMask = nullptr; @@ -651,5 +730,26 @@ for (auto Inst : ToInstrument) Changed |= instrumentMemAccess(Inst); + LocalDynamicShadow = nullptr; + return Changed; } + +void HWAddressSanitizer::ShadowMapping::init(Triple &TargetTriple) { + const bool IsAndroid = TargetTriple.isAndroid(); + const bool IsLinux = TargetTriple.isOSLinux(); + const bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; + const bool IsAndroidWithIfuncSupport = + IsAndroid && !TargetTriple.isAndroidVersionLT(21); + + Scale = kDefaultShadowScale; + + if (ClEnableKhwasan || ClInstrumentWithCalls) + Offset = 0; + else + Offset = kDynamicShadowSentinel; + if (ClMappingOffset.getNumOccurrences() > 0) + Offset = ClMappingOffset; + + InGlobal = (IsX86_64 && IsLinux) || IsAndroidWithIfuncSupport; +} Index: llvm/trunk/test/Instrumentation/HWAddressSanitizer/alloca.ll =================================================================== --- llvm/trunk/test/Instrumentation/HWAddressSanitizer/alloca.ll +++ llvm/trunk/test/Instrumentation/HWAddressSanitizer/alloca.ll @@ -1,6 +1,7 @@ ; Test basic address sanitizer instrumentation. ; -; RUN: opt < %s -hwasan -S | FileCheck %s +; RUN: opt < %s -hwasan -S | FileCheck %s --check-prefixes=CHECK,DYNAMIC-SHADOW +; RUN: opt < %s -hwasan -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ZERO-BASED-SHADOW ; RUN: opt < %s -hwasan -hwasan-generate-tags-with-calls -S | FileCheck %s --check-prefix=WITH-CALLS target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" @@ -25,7 +26,9 @@ ; CHECK: %[[X_TAG2:[^ ]*]] = trunc i64 %[[X_TAG]] to i8 ; CHECK: %[[E:[^ ]*]] = ptrtoint i32* %[[X]] to i64 ; CHECK: %[[F:[^ ]*]] = lshr i64 %[[E]], 4 -; CHECK: %[[X_SHADOW:[^ ]*]] = inttoptr i64 %[[F]] to i8* +; DYNAMIC-SHADOW: %[[F_DYN:[^ ]*]] = add i64 %[[F]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[X_SHADOW:[^ ]*]] = inttoptr i64 %[[F_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[X_SHADOW:[^ ]*]] = inttoptr i64 %[[F]] to i8* ; CHECK: call void @llvm.memset.p0i8.i64(i8* align 1 %[[X_SHADOW]], i8 %[[X_TAG2]], i64 1, i1 false) ; CHECK: call void @use32(i32* nonnull %[[X_HWASAN]]) @@ -33,7 +36,9 @@ ; CHECK: %[[X_TAG_UAR2:[^ ]*]] = trunc i64 %[[X_TAG_UAR]] to i8 ; CHECK: %[[E2:[^ ]*]] = ptrtoint i32* %[[X]] to i64 ; CHECK: %[[F2:[^ ]*]] = lshr i64 %[[E2]], 4 -; CHECK: %[[X_SHADOW2:[^ ]*]] = inttoptr i64 %[[F2]] to i8* +; DYNAMIC-SHADOW: %[[F2_DYN:[^ ]*]] = add i64 %[[F2]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[X_SHADOW2:[^ ]*]] = inttoptr i64 %[[F2_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[X_SHADOW2:[^ ]*]] = inttoptr i64 %[[F2]] to i8* ; CHECK: call void @llvm.memset.p0i8.i64(i8* align 1 %[[X_SHADOW2]], i8 %[[X_TAG_UAR2]], i64 1, i1 false) ; CHECK: ret void Index: llvm/trunk/test/Instrumentation/HWAddressSanitizer/basic.ll =================================================================== --- llvm/trunk/test/Instrumentation/HWAddressSanitizer/basic.ll +++ llvm/trunk/test/Instrumentation/HWAddressSanitizer/basic.ll @@ -1,7 +1,9 @@ ; Test basic address sanitizer instrumentation. ; -; 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 +; RUN: opt < %s -hwasan -hwasan-recover=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,DYNAMIC-SHADOW +; RUN: opt < %s -hwasan -hwasan-recover=1 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,DYNAMIC-SHADOW +; RUN: opt < %s -hwasan -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,ZERO-BASED-SHADOW +; RUN: opt < %s -hwasan -hwasan-recover=1 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,ZERO-BASED-SHADOW target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64--linux-android" @@ -13,7 +15,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -38,7 +42,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -63,7 +69,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -88,7 +96,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -113,7 +123,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -151,7 +163,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -176,7 +190,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -201,7 +217,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -226,7 +244,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -251,7 +271,9 @@ ; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 ; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 ; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 -; CHECK: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* +; DYNAMIC-SHADOW: %[[D_DYN:[^ ]*]] = add i64 %[[D]], %.hwasan.shadow +; DYNAMIC-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D_DYN]] to i8* +; ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8* ; CHECK: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]] ; CHECK: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] ; CHECK: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} @@ -320,6 +342,7 @@ define i8 @test_load_addrspace(i8 addrspace(256)* %a) sanitize_hwaddress { ; CHECK-LABEL: @test_load_addrspace( ; CHECK-NEXT: entry: +; DYNAMIC-SHADOW: %.hwasan.shadow = call i64 asm "", "=r,0"([0 x i8]* @__hwasan_shadow) ; CHECK-NEXT: %[[B:[^ ]*]] = load i8, i8 addrspace(256)* %a ; CHECK-NEXT: ret i8 %[[B]]