blob: f9c345162e2dada5f1241992698f347b3bc03c81 [file] [log] [blame]
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +00001//===- 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"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000034#include "llvm/IR/MDBuilder.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000035#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"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000042#include "llvm/Support/raw_ostream.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000043#include "llvm/Transforms/Instrumentation.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000044#include "llvm/Transforms/Utils/BasicBlockUtils.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000045#include "llvm/Transforms/Utils/ModuleUtils.h"
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000046#include "llvm/Transforms/Utils/PromoteMemToReg.h"
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000047
48using namespace llvm;
49
50#define DEBUG_TYPE "hwasan"
51
52static const char *const kHwasanModuleCtorName = "hwasan.module_ctor";
53static const char *const kHwasanInitName = "__hwasan_init";
54
55// Accesses sizes are powers of two: 1, 2, 4, 8, 16.
56static const size_t kNumberOfAccessSizes = 5;
57
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000058static const size_t kShadowScale = 4;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000059static const unsigned kAllocaAlignment = 1U << kShadowScale;
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000060static const unsigned kPointerTagShift = 56;
61
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000062static 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
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +000067static 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
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000072static cl::opt<bool> ClInstrumentReads("hwasan-instrument-reads",
73 cl::desc("instrument read instructions"),
74 cl::Hidden, cl::init(true));
75
76static cl::opt<bool> ClInstrumentWrites(
77 "hwasan-instrument-writes", cl::desc("instrument write instructions"),
78 cl::Hidden, cl::init(true));
79
80static cl::opt<bool> ClInstrumentAtomics(
81 "hwasan-instrument-atomics",
82 cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
83 cl::init(true));
84
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +000085static cl::opt<bool> ClRecover(
86 "hwasan-recover",
87 cl::desc("Enable recovery mode (continue-after-error)."),
88 cl::Hidden, cl::init(false));
89
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +000090static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
91 cl::desc("instrument stack (allocas)"),
92 cl::Hidden, cl::init(true));
93
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +000094namespace {
95
96/// \brief An instrumentation pass implementing detection of addressability bugs
97/// using tagged pointers.
98class HWAddressSanitizer : public FunctionPass {
99public:
100 // Pass identification, replacement for typeid.
101 static char ID;
102
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000103 HWAddressSanitizer(bool Recover = false)
104 : FunctionPass(ID), Recover(Recover || ClRecover) {}
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000105
106 StringRef getPassName() const override { return "HWAddressSanitizer"; }
107
108 bool runOnFunction(Function &F) override;
109 bool doInitialization(Module &M) override;
110
111 void initializeCallbacks(Module &M);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000112 void instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
113 unsigned AccessSizeIndex,
114 Instruction *InsertBefore);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000115 bool instrumentMemAccess(Instruction *I);
116 Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
117 uint64_t *TypeSize, unsigned *Alignment,
118 Value **MaybeMask);
119
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000120 bool isInterestingAlloca(const AllocaInst &AI);
121 bool tagAlloca(IRBuilder<> &IRB, AllocaInst *AI, Value *Tag);
122 bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
123 SmallVectorImpl<Instruction *> &RetVec);
124
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000125private:
126 LLVMContext *C;
127 Type *IntptrTy;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000128 Type *Int8Ty;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000129
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000130 bool Recover;
131
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000132 Function *HwasanCtorFunction;
133
134 Function *HwasanMemoryAccessCallback[2][kNumberOfAccessSizes];
135 Function *HwasanMemoryAccessCallbackSized[2];
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000136
137 Function *HwasanTagMemoryFunc;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000138};
139
140} // end anonymous namespace
141
142char HWAddressSanitizer::ID = 0;
143
144INITIALIZE_PASS_BEGIN(
145 HWAddressSanitizer, "hwasan",
146 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
147INITIALIZE_PASS_END(
148 HWAddressSanitizer, "hwasan",
149 "HWAddressSanitizer: detect memory bugs using tagged addressing.", false, false)
150
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000151FunctionPass *llvm::createHWAddressSanitizerPass(bool Recover) {
152 return new HWAddressSanitizer(Recover);
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000153}
154
155/// \brief Module-level initialization.
156///
157/// inserts a call to __hwasan_init to the module's constructor list.
158bool HWAddressSanitizer::doInitialization(Module &M) {
159 DEBUG(dbgs() << "Init " << M.getName() << "\n");
160 auto &DL = M.getDataLayout();
161
162 Triple TargetTriple(M.getTargetTriple());
163
164 C = &(M.getContext());
165 IRBuilder<> IRB(*C);
166 IntptrTy = IRB.getIntPtrTy(DL);
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000167 Int8Ty = IRB.getInt8Ty();
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000168
169 std::tie(HwasanCtorFunction, std::ignore) =
170 createSanitizerCtorAndInitFunctions(M, kHwasanModuleCtorName,
171 kHwasanInitName,
172 /*InitArgTypes=*/{},
173 /*InitArgs=*/{});
174 appendToGlobalCtors(M, HwasanCtorFunction, 0);
175 return true;
176}
177
178void HWAddressSanitizer::initializeCallbacks(Module &M) {
179 IRBuilder<> IRB(*C);
180 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
181 const std::string TypeStr = AccessIsWrite ? "store" : "load";
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000182 const std::string EndingStr = Recover ? "_noabort" : "";
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000183
184 HwasanMemoryAccessCallbackSized[AccessIsWrite] =
185 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000186 ClMemoryAccessCallbackPrefix + TypeStr + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000187 FunctionType::get(IRB.getVoidTy(), {IntptrTy, IntptrTy}, false)));
188
189 for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
190 AccessSizeIndex++) {
191 HwasanMemoryAccessCallback[AccessIsWrite][AccessSizeIndex] =
192 checkSanitizerInterfaceFunction(M.getOrInsertFunction(
193 ClMemoryAccessCallbackPrefix + TypeStr +
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000194 itostr(1ULL << AccessSizeIndex) + EndingStr,
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000195 FunctionType::get(IRB.getVoidTy(), {IntptrTy}, false)));
196 }
197 }
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000198
199 HwasanTagMemoryFunc = checkSanitizerInterfaceFunction(M.getOrInsertFunction(
200 "__hwasan_tag_memory", IRB.getVoidTy(), IntptrTy, Int8Ty, IntptrTy));
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000201}
202
203Value *HWAddressSanitizer::isInterestingMemoryAccess(Instruction *I,
204 bool *IsWrite,
205 uint64_t *TypeSize,
206 unsigned *Alignment,
207 Value **MaybeMask) {
208 // Skip memory accesses inserted by another instrumentation.
209 if (I->getMetadata("nosanitize")) return nullptr;
210
211 Value *PtrOperand = nullptr;
212 const DataLayout &DL = I->getModule()->getDataLayout();
213 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
214 if (!ClInstrumentReads) return nullptr;
215 *IsWrite = false;
216 *TypeSize = DL.getTypeStoreSizeInBits(LI->getType());
217 *Alignment = LI->getAlignment();
218 PtrOperand = LI->getPointerOperand();
219 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
220 if (!ClInstrumentWrites) return nullptr;
221 *IsWrite = true;
222 *TypeSize = DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType());
223 *Alignment = SI->getAlignment();
224 PtrOperand = SI->getPointerOperand();
225 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
226 if (!ClInstrumentAtomics) return nullptr;
227 *IsWrite = true;
228 *TypeSize = DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType());
229 *Alignment = 0;
230 PtrOperand = RMW->getPointerOperand();
231 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
232 if (!ClInstrumentAtomics) return nullptr;
233 *IsWrite = true;
234 *TypeSize = DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType());
235 *Alignment = 0;
236 PtrOperand = XCHG->getPointerOperand();
237 }
238
239 if (PtrOperand) {
240 // Do not instrument acesses from different address spaces; we cannot deal
241 // with them.
242 Type *PtrTy = cast<PointerType>(PtrOperand->getType()->getScalarType());
243 if (PtrTy->getPointerAddressSpace() != 0)
244 return nullptr;
245
246 // Ignore swifterror addresses.
247 // swifterror memory addresses are mem2reg promoted by instruction
248 // selection. As such they cannot have regular uses like an instrumentation
249 // function and it makes no sense to track them as memory.
250 if (PtrOperand->isSwiftError())
251 return nullptr;
252 }
253
254 return PtrOperand;
255}
256
257static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
258 size_t Res = countTrailingZeros(TypeSize / 8);
259 assert(Res < kNumberOfAccessSizes);
260 return Res;
261}
262
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000263void HWAddressSanitizer::instrumentMemAccessInline(Value *PtrLong, bool IsWrite,
264 unsigned AccessSizeIndex,
265 Instruction *InsertBefore) {
266 IRBuilder<> IRB(InsertBefore);
267 Value *PtrTag = IRB.CreateTrunc(IRB.CreateLShr(PtrLong, kPointerTagShift), IRB.getInt8Ty());
268 Value *AddrLong =
269 IRB.CreateAnd(PtrLong, ConstantInt::get(PtrLong->getType(),
270 ~(0xFFULL << kPointerTagShift)));
271 Value *ShadowLong = IRB.CreateLShr(AddrLong, kShadowScale);
272 Value *MemTag = IRB.CreateLoad(IRB.CreateIntToPtr(ShadowLong, IRB.getInt8PtrTy()));
273 Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag);
274
275 TerminatorInst *CheckTerm =
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000276 SplitBlockAndInsertIfThen(TagMismatch, InsertBefore, !Recover,
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000277 MDBuilder(*C).createBranchWeights(1, 100000));
278
279 IRB.SetInsertPoint(CheckTerm);
280 // The signal handler will find the data address in x0.
281 InlineAsm *Asm = InlineAsm::get(
282 FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
Evgeniy Stepanov3fd1b1a2017-12-20 19:05:44 +0000283 "hlt #" +
284 itostr(0x100 + Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex),
285 "{x0}",
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000286 /*hasSideEffects=*/true);
287 IRB.CreateCall(Asm, PtrLong);
288}
289
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000290bool HWAddressSanitizer::instrumentMemAccess(Instruction *I) {
291 DEBUG(dbgs() << "Instrumenting: " << *I << "\n");
292 bool IsWrite = false;
293 unsigned Alignment = 0;
294 uint64_t TypeSize = 0;
295 Value *MaybeMask = nullptr;
296 Value *Addr =
297 isInterestingMemoryAccess(I, &IsWrite, &TypeSize, &Alignment, &MaybeMask);
298
299 if (!Addr)
300 return false;
301
302 if (MaybeMask)
303 return false; //FIXME
304
305 IRBuilder<> IRB(I);
306 Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
307 if (isPowerOf2_64(TypeSize) &&
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000308 (TypeSize / 8 <= (1UL << (kNumberOfAccessSizes - 1))) &&
309 (Alignment >= (1UL << kShadowScale) || Alignment == 0 ||
310 Alignment >= TypeSize / 8)) {
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000311 size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
Evgeniy Stepanovecb48e52017-12-13 01:16:34 +0000312 if (ClInstrumentWithCalls) {
313 IRB.CreateCall(HwasanMemoryAccessCallback[IsWrite][AccessSizeIndex],
314 AddrLong);
315 } else {
316 instrumentMemAccessInline(AddrLong, IsWrite, AccessSizeIndex, I);
317 }
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000318 } else {
319 IRB.CreateCall(HwasanMemoryAccessCallbackSized[IsWrite],
320 {AddrLong, ConstantInt::get(IntptrTy, TypeSize / 8)});
321 }
322
323 return true;
324}
325
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000326static uint64_t getAllocaSizeInBytes(const AllocaInst &AI) {
327 uint64_t ArraySize = 1;
328 if (AI.isArrayAllocation()) {
329 const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
330 assert(CI && "non-constant array size");
331 ArraySize = CI->getZExtValue();
332 }
333 Type *Ty = AI.getAllocatedType();
334 uint64_t SizeInBytes = AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
335 return SizeInBytes * ArraySize;
336}
337
338bool HWAddressSanitizer::tagAlloca(IRBuilder<> &IRB, AllocaInst *AI,
339 Value *Tag) {
340 size_t Size = (getAllocaSizeInBytes(*AI) + kAllocaAlignment - 1) &
341 ~(kAllocaAlignment - 1);
342
343 Value *JustTag = IRB.CreateTrunc(Tag, IRB.getInt8Ty());
344 if (ClInstrumentWithCalls) {
345 IRB.CreateCall(HwasanTagMemoryFunc,
346 {IRB.CreatePointerCast(AI, IntptrTy), JustTag,
347 ConstantInt::get(IntptrTy, Size)});
348 } else {
349 size_t ShadowSize = Size >> kShadowScale;
350 Value *ShadowPtr = IRB.CreateIntToPtr(
351 IRB.CreateLShr(IRB.CreatePointerCast(AI, IntptrTy), kShadowScale),
352 IRB.getInt8PtrTy());
353 // If this memset is not inlined, it will be intercepted in the hwasan
354 // runtime library. That's OK, because the interceptor skips the checks if
355 // the address is in the shadow region.
356 // FIXME: the interceptor is not as fast as real memset. Consider lowering
357 // llvm.memset right here into either a sequence of stores, or a call to
358 // hwasan_tag_memory.
359 IRB.CreateMemSet(ShadowPtr, JustTag, ShadowSize, /*Align=*/1);
360 }
361 return true;
362}
363
364static unsigned RetagMask(unsigned AllocaNo) {
365 // A list of 8-bit numbers that have at most one run of non-zero bits.
366 // x = x ^ (mask << 56) can be encoded as a single armv8 instruction for these
367 // masks.
368 // The list does not include the value 255, which is used for UAR.
369 static unsigned FastMasks[] = {
370 0, 1, 2, 3, 4, 6, 7, 8, 12, 14, 15, 16, 24,
371 28, 30, 31, 32, 48, 56, 60, 62, 63, 64, 96, 112, 120,
372 124, 126, 127, 128, 192, 224, 240, 248, 252, 254};
373 return FastMasks[AllocaNo % (sizeof(FastMasks) / sizeof(FastMasks[0]))];
374}
375
376bool HWAddressSanitizer::instrumentStack(
377 SmallVectorImpl<AllocaInst *> &Allocas,
378 SmallVectorImpl<Instruction *> &RetVec) {
379 Function *F = Allocas[0]->getParent()->getParent();
380 Module *M = F->getParent();
381 Instruction *InsertPt = &*F->getEntryBlock().begin();
382 IRBuilder<> IRB(InsertPt);
383
384 // FIXME: use addressofreturnaddress (but implement it in aarch64 backend
385 // first).
386 auto GetStackPointerFn = Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
387 Value *StackPointer = IRB.CreateCall(GetStackPointerFn, {Constant::getNullValue(IRB.getInt32Ty())});
388
389 // Extract some entropy from the stack pointer for the tags.
390 // Take bits 20..28 (ASLR entropy) and xor with bits 0..8 (these differ
391 // between functions).
392 Value *StackPointerLong = IRB.CreatePointerCast(StackPointer, IntptrTy);
393 Value *StackTag =
394 IRB.CreateXor(StackPointerLong, IRB.CreateLShr(StackPointerLong, 20),
395 "hwasan.stack.base.tag");
396
397 // Ideally, we want to calculate tagged stack base pointer, and rewrite all
398 // alloca addresses using that. Unfortunately, offsets are not known yet
399 // (unless we use ASan-style mega-alloca). Instead we keep the base tag in a
400 // temp, shift-OR it into each alloca address and xor with the retag mask.
401 // This generates one extra instruction per alloca use.
402 for (unsigned N = 0; N < Allocas.size(); ++N) {
403 auto *AI = Allocas[N];
404 IRB.SetInsertPoint(AI->getNextNode());
405
406 // Replace uses of the alloca with tagged address.
407 std::string Name =
408 AI->hasName() ? AI->getName().str() : "alloca." + itostr(N);
409 Value *Tag =
410 IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, RetagMask(N)));
411 Value *AILong = IRB.CreatePointerCast(AI, IntptrTy);
412 Value *Replacement = IRB.CreateIntToPtr(
413 IRB.CreateOr(AILong, IRB.CreateShl(Tag, kPointerTagShift)),
414 AI->getType(), Name + ".hwasan");
415
416 for (auto UI = AI->use_begin(), UE = AI->use_end();
417 UI != UE;) {
418 Use &U = *UI++;
419 if (U.getUser() != AILong)
420 U.set(Replacement);
421 }
422
423 tagAlloca(IRB, AI, Tag);
424
425 for (auto RI : RetVec) {
426 IRB.SetInsertPoint(RI);
427
428 // Re-tag alloca memory with the special UAR tag.
429 Value *Tag = IRB.CreateXor(StackTag, ConstantInt::get(IntptrTy, 0xFFU));
430 tagAlloca(IRB, AI, Tag);
431 }
432 }
433
434 return true;
435}
436
437bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
438 return (AI.getAllocatedType()->isSized() &&
439 // FIXME: instrument dynamic allocas, too
440 AI.isStaticAlloca() &&
441 // alloca() may be called with 0 size, ignore it.
442 getAllocaSizeInBytes(AI) > 0 &&
443 // We are only interested in allocas not promotable to registers.
444 // Promotable allocas are common under -O0.
445 !isAllocaPromotable(&AI) &&
446 // inalloca allocas are not treated as static, and we don't want
447 // dynamic alloca instrumentation for them as well.
448 !AI.isUsedWithInAlloca() &&
449 // swifterror allocas are register promoted by ISel
450 !AI.isSwiftError());
451}
452
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000453bool HWAddressSanitizer::runOnFunction(Function &F) {
454 if (&F == HwasanCtorFunction)
455 return false;
456
457 if (!F.hasFnAttribute(Attribute::SanitizeHWAddress))
458 return false;
459
460 DEBUG(dbgs() << "Function: " << F.getName() << "\n");
461
462 initializeCallbacks(*F.getParent());
463
464 bool Changed = false;
465 SmallVector<Instruction*, 16> ToInstrument;
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000466 SmallVector<AllocaInst*, 8> AllocasToInstrument;
467 SmallVector<Instruction*, 8> RetVec;
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000468 for (auto &BB : F) {
469 for (auto &Inst : BB) {
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000470 if (ClInstrumentStack)
471 if (AllocaInst *AI = dyn_cast<AllocaInst>(&Inst)) {
472 // Realign all allocas. We don't want small uninteresting allocas to
473 // hide in instrumented alloca's padding.
474 if (AI->getAlignment() < kAllocaAlignment)
475 AI->setAlignment(kAllocaAlignment);
476 // Instrument some of them.
477 if (isInterestingAlloca(*AI))
478 AllocasToInstrument.push_back(AI);
479 continue;
480 }
481
482 if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst) || isa<CleanupReturnInst>(Inst))
483 RetVec.push_back(&Inst);
484
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000485 Value *MaybeMask = nullptr;
486 bool IsWrite;
487 unsigned Alignment;
488 uint64_t TypeSize;
489 Value *Addr = isInterestingMemoryAccess(&Inst, &IsWrite, &TypeSize,
490 &Alignment, &MaybeMask);
491 if (Addr || isa<MemIntrinsic>(Inst))
492 ToInstrument.push_back(&Inst);
493 }
494 }
495
Evgeniy Stepanov99fa3e72018-01-11 22:53:30 +0000496 if (!AllocasToInstrument.empty())
497 Changed |= instrumentStack(AllocasToInstrument, RetVec);
498
Evgeniy Stepanovc667c1f2017-12-09 00:21:41 +0000499 for (auto Inst : ToInstrument)
500 Changed |= instrumentMemAccess(Inst);
501
502 return Changed;
503}