1 //===- HWAddressSanitizer.cpp - detector of uninitialized reads -------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 /// \file 11 /// This file is a part of HWAddressSanitizer, an address sanity checker 12 /// based on tagged addressing. 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/ADT/Triple.h" 19 #include "llvm/IR/Attributes.h" 20 #include "llvm/IR/BasicBlock.h" 21 #include "llvm/IR/Constant.h" 22 #include "llvm/IR/Constants.h" 23 #include "llvm/IR/DataLayout.h" 24 #include "llvm/IR/DerivedTypes.h" 25 #include "llvm/IR/Function.h" 26 #include "llvm/IR/IRBuilder.h" 27 #include "llvm/IR/InlineAsm.h" 28 #include "llvm/IR/InstVisitor.h" 29 #include "llvm/IR/Instruction.h" 30 #include "llvm/IR/Instructions.h" 31 #include "llvm/IR/IntrinsicInst.h" 32 #include "llvm/IR/Intrinsics.h" 33 #include "llvm/IR/LLVMContext.h" 34 #include "llvm/IR/MDBuilder.h" 35 #include "llvm/IR/Module.h" 36 #include "llvm/IR/Type.h" 37 #include "llvm/IR/Value.h" 38 #include "llvm/Pass.h" 39 #include "llvm/Support/Casting.h" 40 #include "llvm/Support/CommandLine.h" 41 #include "llvm/Support/Debug.h" 42 #include "llvm/Support/raw_ostream.h" 43 #include "llvm/Transforms/Instrumentation.h" 44 #include "llvm/Transforms/Utils/BasicBlockUtils.h" 45 #include "llvm/Transforms/Utils/ModuleUtils.h" 46 #include "llvm/Transforms/Utils/PromoteMemToReg.h" 47 48 using namespace llvm; 49 50 #define DEBUG_TYPE "hwasan" 51 52 static const char *const kHwasanModuleCtorName = "hwasan.module_ctor"; 53 static const char *const kHwasanInitName = "__hwasan_init"; 54 55 // Accesses sizes are powers of two: 1, 2, 4, 8, 16. 56 static const size_t kNumberOfAccessSizes = 5; 57 58 static const size_t kShadowScale = 4; 59 static const unsigned kAllocaAlignment = 1U << kShadowScale; 60 static const unsigned kPointerTagShift = 56; 61 62 static cl::opt<std::string> ClMemoryAccessCallbackPrefix( 63 "hwasan-memory-access-callback-prefix", 64 cl::desc("Prefix for memory access callbacks"), cl::Hidden, 65 cl::init("__hwasan_")); 66 67 static cl::opt<bool> 68 ClInstrumentWithCalls("hwasan-instrument-with-calls", 69 cl::desc("instrument reads and writes with callbacks"), 70 cl::Hidden, cl::init(false)); 71 72 static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads", 73 cl::desc("instrument read instructions"), 74 cl::Hidden, cl::init(true)); 75 76 static cl::opt<bool> ClInstrumentWrites( 77 "hwasan-instrument-writes", cl::desc("instrument write instructions"), 78 cl::Hidden, cl::init(true)); 79 80 static cl::opt<bool> ClInstrumentAtomics( 81 "hwasan-instrument-atomics", 82 cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, 83 cl::init(true)); 84 85 static cl::opt<bool> ClRecover( 86 "hwasan-recover", 87 cl::desc("Enable recovery mode (continue-after-error)."), 88 cl::Hidden, cl::init(false)); 89 90 static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack", 91 cl::desc("instrument stack (allocas)"), 92 cl::Hidden, cl::init(true)); 93 94 static cl::opt<bool> ClGenerateTagsWithCalls( 95 "hwasan-generate-tags-with-calls", 96 cl::desc("generate new tags with runtime library calls"), cl::Hidden, 97 cl::init(false)); 98 99 static cl::opt<unsigned long long> ClMappingOffset( 100 "hwasan-mapping-offset", 101 cl::desc("offset of hwasan shadow mapping [EXPERIMENTAL]"), cl::Hidden, 102 cl::init(0)); 103 104 static cl::opt<bool> ClEnableKhwasan( 105 "hwasan-kernel", cl::desc("Enable KernelHWAddressSanitizer instrumentation"), 106 cl::Hidden, cl::init(false)); 107 108 namespace { 109 110 /// \brief An instrumentation pass implementing detection of addressability bugs 111 /// using tagged pointers. 112 class HWAddressSanitizer : public FunctionPass { 113 public: 114 // Pass identification, replacement for typeid. 115 static char ID; 116 117 HWAddressSanitizer(bool Recover = false) 118 : FunctionPass(ID), Recover(Recover || ClRecover) {} 119 120 StringRef getPassName() const override { return "HWAddressSanitizer"; } 121 122 bool runOnFunction(Function &F) override; 123 bool doInitialization(Module &M) override; 124 125 void initializeCallbacks(Module &M); 126 void instrumentMemAccessInline(Value *PtrLong, bool IsWrite, 127 unsigned AccessSizeIndex, 128 Instruction *InsertBefore); 129 bool instrumentMemAccess(Instruction *I); 130 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite, 131 uint64_t *TypeSize, unsigned *Alignment, 132 Value **MaybeMask); 133 134 bool isInterestingAlloca(const AllocaInst &AI); 135 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag); 136 Value *tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, Value *Tag); 137 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas, 138 SmallVectorImpl<Instruction *> &RetVec); 139 Value *getNextTagWithCall(IRBuilder<> &IRB); 140 Value *getStackBaseTag(IRBuilder<> &IRB); 141 Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI, 142 unsigned AllocaNo); 143 Value *getUARTag(IRBuilder<> &IRB, Value *StackTag); 144 145 private: 146 LLVMContext *C; 147 Type *IntptrTy; 148 Type *Int8Ty; 149 150 bool Recover; 151 152 Function *HwasanCtorFunction; 153 154 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes]; 155 Function *HwasanMemoryAccessCallbackSized[2]; 156 157 Function *HwasanTagMemoryFunc; 158 Function *HwasanGenerateTagFunc; 159 }; 160 161 } // end anonymous namespace 162 163 char HWAddressSanitizer::ID = 0; 164 165 INITIALIZE_PASS_BEGIN( 166 HWAddressSanitizer, "hwasan", 167 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) 168 INITIALIZE_PASS_END( 169 HWAddressSanitizer, "hwasan", 170 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false) 171 172 FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) { 173 return new HWAddressSanitizer(Recover); 174 } 175 176 /// \brief Module-level initialization. 177 /// 178 /// inserts a call to __hwasan_init to the module's constructor list. 179 bool HWAddressSanitizer::doInitialization(Module &M) { 180 DEBUG(dbgs() << "Init " << M.getName() << "\n"); 181 auto &DL = M.getDataLayout(); 182 183 Triple TargetTriple(M.getTargetTriple()); 184 185 C = &(M.getContext()); 186 IRBuilder<> IRB(*C); 187 IntptrTy = IRB.getIntPtrTy(DL); 188 Int8Ty = IRB.getInt8Ty(); 189 190 HwasanCtorFunction = nullptr; 191 if (!ClEnableKhwasan) { 192 std::tie(HwasanCtorFunction, std::ignore) = 193 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName, 194 kHwasanInitName, 195 /*InitArgTypes=*/{}, 196 /*InitArgs=*/{}); 197 appendToGlobalCtors(M, HwasanCtorFunction, 0); 198 } 199 return true; 200 } 201 202 void HWAddressSanitizer::initializeCallbacks(Module &M) { 203 IRBuilder<> IRB(*C); 204 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) { 205 const std::string TypeStr = AccessIsWrite ? "store" : "load"; 206 const std::string EndingStr = Recover ? "_noabort" : ""; 207 208 HwasanMemoryAccessCallbackSized[AccessIsWrite] = 209 checkSanitizerInterfaceFunction(M.getOrInsertFunction( 210 ClMemoryAccessCallbackPrefix + TypeStr + "N" + EndingStr, 211 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false))); 212 213 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes; 214 AccessSizeIndex++) { 215 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] = 216 checkSanitizerInterfaceFunction(M.getOrInsertFunction( 217 ClMemoryAccessCallbackPrefix + TypeStr + 218 itostr(1ULL << AccessSizeIndex) + EndingStr, 219 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false))); 220 } 221 } 222 223 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction( 224 "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy)); 225 HwasanGenerateTagFunc = checkSanitizerInterfaceFunction( 226 M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty)); 227 } 228 229 Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I, 230 bool *IsWrite, 231 uint64_t *TypeSize, 232 unsigned *Alignment, 233 Value **MaybeMask) { 234 // Skip memory accesses inserted by another instrumentation. 235 if (I->getMetadata("nosanitize")) return nullptr; 236 237 Value *PtrOperand = nullptr; 238 const DataLayout &DL = I->getModule()->getDataLayout(); 239 if (LoadInst *LI = dyn_cast<LoadInst>(I)) { 240 if (!ClInstrumentReads) return nullptr; 241 *IsWrite = false; 242 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType()); 243 *Alignment = LI->getAlignment(); 244 PtrOperand = LI->getPointerOperand(); 245 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { 246 if (!ClInstrumentWrites) return nullptr; 247 *IsWrite = true; 248 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType()); 249 *Alignment = SI->getAlignment(); 250 PtrOperand = SI->getPointerOperand(); 251 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { 252 if (!ClInstrumentAtomics) return nullptr; 253 *IsWrite = true; 254 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType()); 255 *Alignment = 0; 256 PtrOperand = RMW->getPointerOperand(); 257 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { 258 if (!ClInstrumentAtomics) return nullptr; 259 *IsWrite = true; 260 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType()); 261 *Alignment = 0; 262 PtrOperand = XCHG->getPointerOperand(); 263 } 264 265 if (PtrOperand) { 266 // Do not instrument acesses from different address spaces; we cannot deal 267 // with them. 268 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType()); 269 if (PtrTy->getPointerAddressSpace() != 0) 270 return nullptr; 271 272 // Ignore swifterror addresses. 273 // swifterror memory addresses are mem2reg promoted by instruction 274 // selection. As such they cannot have regular uses like an instrumentation 275 // function and it makes no sense to track them as memory. 276 if (PtrOperand->isSwiftError()) 277 return nullptr; 278 } 279 280 return PtrOperand; 281 } 282 283 static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { 284 size_t Res = countTrailingZeros(TypeSize / 8); 285 assert(Res < kNumberOfAccessSizes); 286 return Res; 287 } 288 289 void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite, 290 unsigned AccessSizeIndex, 291 Instruction *InsertBefore) { 292 IRBuilder<> IRB(InsertBefore); 293 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty()); 294 Value *AddrLong = 295 IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(), 296 ~(0xFFULL << kPointerTagShift))); 297 Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale); 298 if (ClMappingOffset) 299 ShadowLong = IRB.CreateAdd( 300 ShadowLong, ConstantInt::get(PtrLong->getType(), ClMappingOffset, 301 /*isSigned=*/false)); 302 Value *MemTag = 303 IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy())); 304 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag); 305 306 TerminatorInst *CheckTerm = 307 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover, 308 MDBuilder(*C).createBranchWeights(1, 100000)); 309 310 IRB.SetInsertPoint(CheckTerm); 311 // The signal handler will find the data address in x0. 312 InlineAsm *Asm = InlineAsm::get( 313 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), 314 "hlt #" + 315 itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex), 316 "{x0}", 317 /*hasSideEffects=*/true); 318 IRB.CreateCall(Asm, PtrLong); 319 } 320 321 bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) { 322 DEBUG(dbgs() << "Instrumenting: " << *I << "\n"); 323 bool IsWrite = false; 324 unsigned Alignment = 0; 325 uint64_t TypeSize = 0; 326 Value *MaybeMask = nullptr; 327 Value *Addr = 328 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask); 329 330 if (!Addr) 331 return false; 332 333 if (MaybeMask) 334 return false; //FIXME 335 336 IRBuilder<> IRB(I); 337 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); 338 if (isPowerOf2_64(TypeSize) && 339 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) && 340 (Alignment >= (1UL << kShadowScale) || Alignment == 0 || 341 Alignment >= TypeSize / 8)) { 342 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize); 343 if (ClInstrumentWithCalls) { 344 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex], 345 AddrLong); 346 } else { 347 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I); 348 } 349 } else { 350 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite], 351 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)}); 352 } 353 354 return true; 355 } 356 357 static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) { 358 uint64_t ArraySize = 1; 359 if (AI.isArrayAllocation()) { 360 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize()); 361 assert(CI && "non-constant array size"); 362 ArraySize = CI->getZExtValue(); 363 } 364 Type *Ty = AI.getAllocatedType(); 365 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty); 366 return SizeInBytes * ArraySize; 367 } 368 369 bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, 370 Value *Tag) { 371 size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) & 372 ~(kAllocaAlignment - 1); 373 374 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty()); 375 if (ClInstrumentWithCalls) { 376 IRB.CreateCall(HwasanTagMemoryFunc, 377 {IRB.CreatePointerCast(AI, IntptrTy), JustTag, 378 ConstantInt::get(IntptrTy, Size)}); 379 } else { 380 size_t ShadowSize = Size >> kShadowScale; 381 Value *ShadowPtr = IRB.CreateIntToPtr( 382 IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale), 383 IRB.getInt8PtrTy()); 384 // If this memset is not inlined, it will be intercepted in the hwasan 385 // runtime library. That's OK, because the interceptor skips the checks if 386 // the address is in the shadow region. 387 // FIXME: the interceptor is not as fast as real memset. Consider lowering 388 // llvm.memset right here into either a sequence of stores, or a call to 389 // hwasan_tag_memory. 390 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1); 391 } 392 return true; 393 } 394 395 static unsigned RetagMask(unsigned AllocaNo) { 396 // A list of 8-bit numbers that have at most one run of non-zero bits. 397 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these 398 // masks. 399 // The list does not include the value 255, which is used for UAR. 400 static unsigned FastMasks[] = { 401 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24, 402 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120, 403 124, 126, 127, 128, 192, 224, 240, 248, 252, 254}; 404 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))]; 405 } 406 407 Value *HWAddressSanitizer::getNextTagWithCall(IRBuilder<> &IRB) { 408 return IRB.CreateZExt(IRB.CreateCall(HwasanGenerateTagFunc), IntptrTy); 409 } 410 411 Value *HWAddressSanitizer::getStackBaseTag(IRBuilder<> &IRB) { 412 if (ClGenerateTagsWithCalls) 413 return nullptr; 414 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend 415 // first). 416 Module *M = IRB.GetInsertBlock()->getParent()->getParent(); 417 auto GetStackPointerFn = 418 Intrinsic::getDeclaration(M, Intrinsic::frameaddress); 419 Value *StackPointer = IRB.CreateCall( 420 GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())}); 421 422 // Extract some entropy from the stack pointer for the tags. 423 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ 424 // between functions). 425 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy); 426 Value *StackTag = 427 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20), 428 "hwasan.stack.base.tag"); 429 return StackTag; 430 } 431 432 Value *HWAddressSanitizer::getAllocaTag(IRBuilder<> &IRB, Value *StackTag, 433 AllocaInst *AI, unsigned AllocaNo) { 434 if (ClGenerateTagsWithCalls) 435 return getNextTagWithCall(IRB); 436 return IRB.CreateXor(StackTag, 437 ConstantInt::get(IntptrTy, RetagMask(AllocaNo))); 438 } 439 440 Value *HWAddressSanitizer::getUARTag(IRBuilder<> &IRB, Value *StackTag) { 441 if (ClGenerateTagsWithCalls) 442 return getNextTagWithCall(IRB); 443 return IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU)); 444 } 445 446 // Add a tag to an address. 447 Value *HWAddressSanitizer::tagPointer(IRBuilder<> &IRB, Type *Ty, Value *PtrLong, 448 Value *Tag) { 449 Value *TaggedPtrLong; 450 if (ClEnableKhwasan) { 451 // Kernel addresses have 0xFF in the most significant byte. 452 Value *ShiftedTag = IRB.CreateOr( 453 IRB.CreateShl(Tag, kPointerTagShift), 454 ConstantInt::get(IntptrTy, (1ULL << kPointerTagShift) - 1)); 455 TaggedPtrLong = IRB.CreateAnd(PtrLong, ShiftedTag); 456 } else { 457 // Userspace can simply do OR (tag << 56); 458 Value *ShiftedTag = IRB.CreateShl(Tag, kPointerTagShift); 459 TaggedPtrLong = IRB.CreateOr(PtrLong, ShiftedTag); 460 } 461 return IRB.CreateIntToPtr(TaggedPtrLong, Ty); 462 } 463 464 bool HWAddressSanitizer::instrumentStack( 465 SmallVectorImpl<AllocaInst *> &Allocas, 466 SmallVectorImpl<Instruction *> &RetVec) { 467 Function *F = Allocas[0]->getParent()->getParent(); 468 Instruction *InsertPt = &*F->getEntryBlock().begin(); 469 IRBuilder<> IRB(InsertPt); 470 471 Value *StackTag = getStackBaseTag(IRB); 472 473 // Ideally, we want to calculate tagged stack base pointer, and rewrite all 474 // alloca addresses using that. Unfortunately, offsets are not known yet 475 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a 476 // temp, shift-OR it into each alloca address and xor with the retag mask. 477 // This generates one extra instruction per alloca use. 478 for (unsigned N = 0; N < Allocas.size(); ++N) { 479 auto *AI = Allocas[N]; 480 IRB.SetInsertPoint(AI->getNextNode()); 481 482 // Replace uses of the alloca with tagged address. 483 Value *Tag = getAllocaTag(IRB, StackTag, AI, N); 484 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy); 485 Value *Replacement = tagPointer(IRB, AI->getType(), AILong, Tag); 486 std::string Name = 487 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N); 488 Replacement->setName(Name + ".hwasan"); 489 490 for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) { 491 Use &U = *UI++; 492 if (U.getUser() != AILong) 493 U.set(Replacement); 494 } 495 496 tagAlloca(IRB, AI, Tag); 497 498 for (auto RI : RetVec) { 499 IRB.SetInsertPoint(RI); 500 501 // Re-tag alloca memory with the special UAR tag. 502 Value *Tag = getUARTag(IRB, StackTag); 503 tagAlloca(IRB, AI, Tag); 504 } 505 } 506 507 return true; 508 } 509 510 bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) { 511 return (AI.getAllocatedType()->isSized() && 512 // FIXME: instrument dynamic allocas, too 513 AI.isStaticAlloca() && 514 // alloca() may be called with 0 size, ignore it. 515 getAllocaSizeInBytes(AI) > 0 && 516 // We are only interested in allocas not promotable to registers. 517 // Promotable allocas are common under -O0. 518 !isAllocaPromotable(&AI) && 519 // inalloca allocas are not treated as static, and we don't want 520 // dynamic alloca instrumentation for them as well. 521 !AI.isUsedWithInAlloca() && 522 // swifterror allocas are register promoted by ISel 523 !AI.isSwiftError()); 524 } 525 526 bool HWAddressSanitizer::runOnFunction(Function &F) { 527 if (&F == HwasanCtorFunction) 528 return false; 529 530 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress)) 531 return false; 532 533 DEBUG(dbgs() << "Function: " << F.getName() << "\n"); 534 535 initializeCallbacks(*F.getParent()); 536 537 bool Changed = false; 538 SmallVector<Instruction*, 16> ToInstrument; 539 SmallVector<AllocaInst*, 8> AllocasToInstrument; 540 SmallVector<Instruction*, 8> RetVec; 541 for (auto &BB : F) { 542 for (auto &Inst : BB) { 543 if (ClInstrumentStack) 544 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) { 545 // Realign all allocas. We don't want small uninteresting allocas to 546 // hide in instrumented alloca's padding. 547 if (AI->getAlignment() < kAllocaAlignment) 548 AI->setAlignment(kAllocaAlignment); 549 // Instrument some of them. 550 if (isInterestingAlloca(*AI)) 551 AllocasToInstrument.push_back(AI); 552 continue; 553 } 554 555 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) || isa<CleanupReturnInst>(Inst)) 556 RetVec.push_back(&Inst); 557 558 Value *MaybeMask = nullptr; 559 bool IsWrite; 560 unsigned Alignment; 561 uint64_t TypeSize; 562 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize, 563 &Alignment, &MaybeMask); 564 if (Addr || isa<MemIntrinsic>(Inst)) 565 ToInstrument.push_back(&Inst); 566 } 567 } 568 569 if (!AllocasToInstrument.empty()) 570 Changed |= instrumentStack(AllocasToInstrument, RetVec); 571 572 for (auto Inst : ToInstrument) 573 Changed |= instrumentMemAccess(Inst); 574 575 return Changed; 576 } 577