#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/BinaryFormat/ELF.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
+#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Casting.h"
void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI);
+ std::map<std::pair<unsigned, uint32_t>, MCSymbol *> HwasanMemaccessSymbols;
+ void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
+ void EmitHwasanMemaccessSymbols(Module &M);
+
void EmitSled(const MachineInstr &MI, SledKind Kind);
/// tblgen'erated driver function for lowering simple MI->MC
recordSled(CurSled, MI, Kind);
}
+void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
+ unsigned Reg = MI.getOperand(0).getReg();
+ uint32_t AccessInfo = MI.getOperand(1).getImm();
+ MCSymbol *&Sym = HwasanMemaccessSymbols[{Reg, AccessInfo}];
+ if (!Sym) {
+ // FIXME: Make this work on non-ELF.
+ if (!TM.getTargetTriple().isOSBinFormatELF())
+ report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
+
+ std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" +
+ utostr(AccessInfo);
+ Sym = OutContext.getOrCreateSymbol(SymName);
+ }
+
+ EmitToStreamer(*OutStreamer,
+ MCInstBuilder(AArch64::BL)
+ .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
+}
+
+void AArch64AsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
+ if (HwasanMemaccessSymbols.empty())
+ return;
+
+ const Triple &TT = TM.getTargetTriple();
+ assert(TT.isOSBinFormatELF());
+ std::unique_ptr<MCSubtargetInfo> STI(
+ TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
+
+ MCSymbol *HwasanTagMismatchSym =
+ OutContext.getOrCreateSymbol("__hwasan_tag_mismatch");
+
+ for (auto &P : HwasanMemaccessSymbols) {
+ unsigned Reg = P.first.first;
+ uint32_t AccessInfo = P.first.second;
+ MCSymbol *Sym = P.second;
+
+ OutStreamer->SwitchSection(OutContext.getELFSection(
+ ".text.hot", ELF::SHT_PROGBITS,
+ ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0,
+ Sym->getName()));
+
+ OutStreamer->EmitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
+ OutStreamer->EmitSymbolAttribute(Sym, MCSA_Weak);
+ OutStreamer->EmitSymbolAttribute(Sym, MCSA_Hidden);
+ OutStreamer->EmitLabel(Sym);
+
+ OutStreamer->EmitInstruction(MCInstBuilder(AArch64::UBFMXri)
+ .addReg(AArch64::X16)
+ .addReg(Reg)
+ .addImm(4)
+ .addImm(55),
+ *STI);
+ OutStreamer->EmitInstruction(MCInstBuilder(AArch64::LDRBBroX)
+ .addReg(AArch64::W16)
+ .addReg(AArch64::X9)
+ .addReg(AArch64::X16)
+ .addImm(0)
+ .addImm(0),
+ *STI);
+ OutStreamer->EmitInstruction(MCInstBuilder(AArch64::UBFMXri)
+ .addReg(AArch64::X17)
+ .addReg(Reg)
+ .addImm(56)
+ .addImm(63),
+ *STI);
+ OutStreamer->EmitInstruction(MCInstBuilder(AArch64::SUBSWrs)
+ .addReg(AArch64::WZR)
+ .addReg(AArch64::W16)
+ .addReg(AArch64::W17)
+ .addImm(0),
+ *STI);
+ MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
+ OutStreamer->EmitInstruction(
+ MCInstBuilder(AArch64::Bcc)
+ .addImm(AArch64CC::NE)
+ .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
+ *STI);
+ OutStreamer->EmitInstruction(
+ MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI);
+
+ OutStreamer->EmitLabel(HandleMismatchSym);
+ if (Reg != AArch64::X0)
+ OutStreamer->EmitInstruction(MCInstBuilder(AArch64::ORRXrs)
+ .addReg(AArch64::X0)
+ .addReg(AArch64::XZR)
+ .addReg(Reg)
+ .addImm(0),
+ *STI);
+ OutStreamer->EmitInstruction(MCInstBuilder(AArch64::MOVZXi)
+ .addReg(AArch64::X1)
+ .addImm(AccessInfo)
+ .addImm(0),
+ *STI);
+ OutStreamer->EmitInstruction(
+ MCInstBuilder(AArch64::B)
+ .addExpr(MCSymbolRefExpr::create(HwasanTagMismatchSym, OutContext)),
+ *STI);
+ }
+}
+
void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
+ EmitHwasanMemaccessSymbols(M);
+
const Triple &TT = TM.getTargetTriple();
if (TT.isOSBinFormatMachO()) {
// Funny Darwin hack: This flag tells the linker that no global symbols
LowerPATCHABLE_TAIL_CALL(*MI);
return;
+ case AArch64::HWASAN_CHECK_MEMACCESS:
+ LowerHWASAN_CHECK_MEMACCESS(*MI);
+ return;
+
case AArch64::SEH_StackAlloc:
TS->EmitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
return;
ClInstrumentMemIntrinsics("hwasan-instrument-mem-intrinsics",
cl::desc("instrument memory intrinsics"),
cl::Hidden, cl::init(true));
+
+static cl::opt<bool> ClInlineAllChecks("hwasan-inline-all-checks",
+ cl::desc("inline all checks"),
+ cl::Hidden, cl::init(false));
+
namespace {
/// An instrumentation pass implementing detection of addressability bugs
Value *getDynamicShadowNonTls(IRBuilder<> &IRB);
void untagPointerOperand(Instruction *I, Value *Addr);
- Value *memToShadow(Value *Shadow, Type *Ty, IRBuilder<> &IRB);
- void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
+ Value *shadowBase();
+ Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
+ void instrumentMemAccessInline(Value *Ptr, bool IsWrite,
unsigned AccessSizeIndex,
Instruction *InsertBefore);
void instrumentMemIntrinsic(MemIntrinsic *MI);
Type *IntptrTy;
Type *Int8PtrTy;
Type *Int8Ty;
+ Type *Int32Ty;
bool CompileKernel;
bool Recover;
IntptrTy = IRB.getIntPtrTy(DL);
Int8PtrTy = IRB.getInt8PtrTy();
Int8Ty = IRB.getInt8Ty();
+ Int32Ty = IRB.getInt32Ty();
HwasanCtorFunction = nullptr;
if (!CompileKernel) {
if (Mapping.InGlobal) {
// An empty inline asm with input reg == output reg.
- // An opaque pointer-to-int cast, basically.
+ // An opaque no-op cast, basically.
InlineAsm *Asm = InlineAsm::get(
- FunctionType::get(IntptrTy, {ShadowGlobal->getType()}, false),
+ FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false),
StringRef(""), StringRef("=r,0"),
/*hasSideEffects=*/false);
return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
} else {
Value *GlobalDynamicAddress =
IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
- kHwasanShadowMemoryDynamicAddress, IntptrTy);
+ kHwasanShadowMemoryDynamicAddress, Int8PtrTy);
return IRB.CreateLoad(GlobalDynamicAddress);
}
}
I->setOperand(getPointerOperandIndex(I), UntaggedPtr);
}
-Value *HWAddressSanitizer::memToShadow(Value *Mem, Type *Ty, IRBuilder<> &IRB) {
+Value *HWAddressSanitizer::shadowBase() {
+ if (LocalDynamicShadow)
+ return LocalDynamicShadow;
+ return ConstantExpr::getIntToPtr(ConstantInt::get(IntptrTy, Mapping.Offset),
+ Int8PtrTy);
+}
+
+Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) {
// Mem >> Scale
Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale);
if (Mapping.Offset == 0)
- return Shadow;
+ return IRB.CreateIntToPtr(Shadow, Int8PtrTy);
// (Mem >> Scale) + Offset
- Value *ShadowBase;
- if (LocalDynamicShadow)
- ShadowBase = LocalDynamicShadow;
- else
- ShadowBase = ConstantInt::get(Ty, Mapping.Offset);
- return IRB.CreateAdd(Shadow, ShadowBase);
+ return IRB.CreateGEP(Int8Ty, shadowBase(), Shadow);
}
-void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
+void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite,
unsigned AccessSizeIndex,
Instruction *InsertBefore) {
+ const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
IRBuilder<> IRB(InsertBefore);
+
+ if (!ClInlineAllChecks && TargetTriple.isAArch64() &&
+ TargetTriple.isOSBinFormatELF() && !Recover) {
+ Module *M = IRB.GetInsertBlock()->getParent()->getParent();
+ Ptr = IRB.CreateBitCast(Ptr, Int8PtrTy);
+ IRB.CreateCall(
+ Intrinsic::getDeclaration(M, Intrinsic::hwasan_check_memaccess),
+ {shadowBase(), Ptr, ConstantInt::get(Int32Ty, AccessInfo)});
+ return;
+ }
+
+ Value *PtrLong = IRB.CreatePointerCast(Ptr, IntptrTy);
Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift),
IRB.getInt8Ty());
Value *AddrLong = untagPointer(IRB, PtrLong);
- Value *ShadowLong = memToShadow(AddrLong, PtrLong->getType(), IRB);
- Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, Int8PtrTy));
+ Value *Shadow = memToShadow(AddrLong, IRB);
+ Value *MemTag = IRB.CreateLoad(Shadow);
Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ?
MDBuilder(*C).createBranchWeights(1, 100000));
IRB.SetInsertPoint(CheckTerm);
- const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex;
InlineAsm *Asm;
switch (TargetTriple.getArch()) {
case Triple::x86_64:
return false; //FIXME
IRBuilder<> IRB(I);
- Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
if (isPowerOf2_64(TypeSize) &&
(TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
(Alignment >= (1UL << Mapping.Scale) || Alignment == 0 ||
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
if (ClInstrumentWithCalls) {
IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
- AddrLong);
+ IRB.CreatePointerCast(Addr, IntptrTy));
} else {
- instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
+ instrumentMemAccessInline(Addr, IsWrite, AccessSizeIndex, I);
}
} else {
IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
- {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
+ {IRB.CreatePointerCast(Addr, IntptrTy),
+ ConstantInt::get(IntptrTy, TypeSize / 8)});
}
untagPointerOperand(I, Addr);
ConstantInt::get(IntptrTy, Size)});
} else {
size_t ShadowSize = Size >> Mapping.Scale;
- Value *ShadowPtr = IRB.CreateIntToPtr(
- memToShadow(IRB.CreatePointerCast(AI, IntptrTy), AI->getType(), IRB),
- Int8PtrTy);
+ Value *ShadowPtr = memToShadow(IRB.CreatePointerCast(AI, IntptrTy), IRB);
// 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
// the address is in the shadow region.
ThreadLongMaybeUntagged,
ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)),
ConstantInt::get(IntptrTy, 1), "hwasan.shadow");
+ ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy);
return ShadowBase;
}
; Test basic address sanitizer instrumentation.
;
-; RUN: opt < %s -hwasan -hwasan-recover=0 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,DYNAMIC-SHADOW
-; RUN: opt < %s -hwasan -hwasan-recover=1 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -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
+; RUN: opt < %s -hwasan -hwasan-recover=0 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,ABORT-DYNAMIC-SHADOW
+; RUN: opt < %s -hwasan -hwasan-recover=1 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-DYNAMIC-SHADOW
+; RUN: opt < %s -hwasan -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT,ABORT-ZERO-BASED-SHADOW
+; RUN: opt < %s -hwasan -hwasan-recover=1 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-ZERO-BASED-SHADOW
; CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @hwasan.module_ctor, i8* bitcast (void ()* @hwasan.module_ctor to i8*) }]
; CHECK: @__hwasan = private constant [0 x i8] zeroinitializer, section "__hwasan_frames", comdat($hwasan.module_ctor)
define i8 @test_load8(i8* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load8(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2304", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2336", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %a, i32 0)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %a, i32 0)
+
; CHECK: %[[G:[^ ]*]] = load i8, i8* %a, align 4
; CHECK: ret i8 %[[G]]
define i16 @test_load16(i16* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load16(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2305", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2337", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i16* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 1)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 1)
+
; CHECK: %[[G:[^ ]*]] = load i16, i16* %a, align 4
; CHECK: ret i16 %[[G]]
define i32 @test_load32(i32* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load32(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2306", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2338", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i32* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 2)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 2)
+
; CHECK: %[[G:[^ ]*]] = load i32, i32* %a, align 4
; CHECK: ret i32 %[[G]]
define i64 @test_load64(i64* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load64(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2307", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2339", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i64* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 3)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 3)
+
; CHECK: %[[G:[^ ]*]] = load i64, i64* %a, align 8
; CHECK: ret i64 %[[G]]
define i128 @test_load128(i128* %a) sanitize_hwaddress {
; CHECK-LABEL: @test_load128(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2308", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2340", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i128* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 4)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 4)
+
; CHECK: %[[G:[^ ]*]] = load i128, i128* %a, align 16
; CHECK: ret i128 %[[G]]
define void @test_store8(i8* %a, i8 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store8(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2320", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2352", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %a, i32 16)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %a, i32 16)
+
; CHECK: store i8 %b, i8* %a, align 4
; CHECK: ret void
define void @test_store16(i16* %a, i16 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store16(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2321", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2353", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i16* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 17)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 17)
+
; CHECK: store i16 %b, i16* %a, align 4
; CHECK: ret void
define void @test_store32(i32* %a, i32 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store32(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2322", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2354", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i32* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 18)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 18)
+
; CHECK: store i32 %b, i32* %a, align 4
; CHECK: ret void
define void @test_store64(i64* %a, i64 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store64(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2323", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2355", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i64* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 19)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 19)
+
; CHECK: store i64 %b, i64* %a, align 8
; CHECK: ret void
define void @test_store128(i128* %a, i128 %b) sanitize_hwaddress {
; CHECK-LABEL: @test_store128(
-; CHECK: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
-; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
-; CHECK: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
-; CHECK: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
-; CHECK: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
-; 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 {{.*}}
-
-; ABORT: call void asm sideeffect "brk #2324", "{x0}"(i64 %[[A]])
-; ABORT: unreachable
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
; RECOVER: call void asm sideeffect "brk #2356", "{x0}"(i64 %[[A]])
; RECOVER: br label
+; ABORT: %[[A:[^ ]*]] = bitcast i128* %a to i8*
+; ABORT-DYNAMIC-SHADOW: call void @llvm.hwasan.check.memaccess(i8* %.hwasan.shadow, i8* %[[A]], i32 20)
+; ABORT-ZERO-BASED-SHADOW: call void @llvm.hwasan.check.memaccess(i8* null, i8* %[[A]], i32 20)
+
; CHECK: store i128 %b, i128* %a, align 16
; CHECK: ret void