blob: 2ed65ebbab11682b1925af9bd519ab0bbb9a0697 [file] [log] [blame]
Nuno Lopes5c525b52012-05-22 17:19:09 +00001//===- BoundsChecking.cpp - Instrumentation for run-time bounds checking --===//
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// This file implements a pass that instruments the code to perform run-time
11// bounds checking on loads, stores, and other memory intrinsics.
12//
13//===----------------------------------------------------------------------===//
14
15#define DEBUG_TYPE "bounds-checking"
16#include "llvm/Transforms/Scalar.h"
Nuno Lopes0463cce2012-05-31 22:45:40 +000017#include "llvm/ADT/DenseMap.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000018#include "llvm/ADT/Statistic.h"
Nuno Lopes988a0892012-05-29 22:32:51 +000019#include "llvm/Analysis/LoopInfo.h"
20#include "llvm/Analysis/ScalarEvolution.h"
21#include "llvm/Analysis/ScalarEvolutionExpander.h"
22#include "llvm/Analysis/ScalarEvolutionExpressions.h"
Nuno Lopes1cbf2be2012-05-31 22:58:48 +000023#include "llvm/Support/CommandLine.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000024#include "llvm/Support/Debug.h"
25#include "llvm/Support/InstIterator.h"
26#include "llvm/Support/IRBuilder.h"
Nuno Lopes2f0a7482012-05-22 22:02:19 +000027#include "llvm/Support/raw_ostream.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000028#include "llvm/Support/TargetFolder.h"
29#include "llvm/Target/TargetData.h"
30#include "llvm/Transforms/Utils/Local.h"
31#include "llvm/GlobalVariable.h"
32#include "llvm/Instructions.h"
33#include "llvm/Intrinsics.h"
Nuno Lopes6a06e682012-05-25 16:54:04 +000034#include "llvm/Metadata.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000035#include "llvm/Operator.h"
36#include "llvm/Pass.h"
37using namespace llvm;
38
Nuno Lopes1cbf2be2012-05-31 22:58:48 +000039static cl::opt<bool> ManyTrapBB("bounds-checking-multiple-traps",
40 cl::desc("Use one trap block per assertion"));
41
Nuno Lopes5c525b52012-05-22 17:19:09 +000042STATISTIC(ChecksAdded, "Bounds checks added");
43STATISTIC(ChecksSkipped, "Bounds checks skipped");
44STATISTIC(ChecksUnable, "Bounds checks unable to add");
Nuno Lopes988a0892012-05-29 22:32:51 +000045STATISTIC(ChecksUnableInterproc, "Bounds checks unable to add (interprocedural)");
46STATISTIC(ChecksUnableLoad, "Bounds checks unable to add (LoadInst)");
Nuno Lopes5c525b52012-05-22 17:19:09 +000047
48typedef IRBuilder<true, TargetFolder> BuilderTy;
49
50namespace {
Nuno Lopes0463cce2012-05-31 22:45:40 +000051 // FIXME: can use unions here to save space
52 struct CacheData {
53 APInt Offset;
54 Value *OffsetValue;
55 APInt Size;
56 Value *SizeValue;
57 bool ReturnVal;
Nuno Lopes5c525b52012-05-22 17:19:09 +000058 };
Nuno Lopes0463cce2012-05-31 22:45:40 +000059 typedef DenseMap<Value*, CacheData> CacheMapTy;
Nuno Lopes5c525b52012-05-22 17:19:09 +000060
61 struct BoundsChecking : public FunctionPass {
Nuno Lopes5c525b52012-05-22 17:19:09 +000062 static char ID;
63
64 BoundsChecking(unsigned _Penalty = 5) : FunctionPass(ID), Penalty(_Penalty){
65 initializeBoundsCheckingPass(*PassRegistry::getPassRegistry());
66 }
67
Nuno Lopes5c525b52012-05-22 17:19:09 +000068 virtual bool runOnFunction(Function &F);
69
70 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
71 AU.addRequired<TargetData>();
Nuno Lopes988a0892012-05-29 22:32:51 +000072 AU.addRequired<LoopInfo>();
73 AU.addRequired<ScalarEvolution>();
Nuno Lopes5c525b52012-05-22 17:19:09 +000074 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +000075
76 private:
77 const TargetData *TD;
Nuno Lopes988a0892012-05-29 22:32:51 +000078 LoopInfo *LI;
79 ScalarEvolution *SE;
Nuno Lopes2f0a7482012-05-22 22:02:19 +000080 BuilderTy *Builder;
81 Function *Fn;
82 BasicBlock *TrapBB;
83 unsigned Penalty;
Nuno Lopes0463cce2012-05-31 22:45:40 +000084 CacheMapTy CacheMap;
Nuno Lopes2f0a7482012-05-22 22:02:19 +000085
86 BasicBlock *getTrapBB();
Nuno Lopes2b526302012-05-23 16:24:52 +000087 void emitBranchToTrap(Value *Cmp = 0);
Nuno Lopes0463cce2012-05-31 22:45:40 +000088 bool computeAllocSize(Value *Ptr, APInt &Offset, Value* &OffsetValue,
89 APInt &Size, Value* &SizeValue);
Nuno Lopes2f0a7482012-05-22 22:02:19 +000090 bool instrument(Value *Ptr, Value *Val);
Nuno Lopes5c525b52012-05-22 17:19:09 +000091 };
92}
93
94char BoundsChecking::ID = 0;
Nuno Lopes988a0892012-05-29 22:32:51 +000095INITIALIZE_PASS_BEGIN(BoundsChecking, "bounds-checking",
96 "Run-time bounds checking", false, false)
97INITIALIZE_PASS_DEPENDENCY(ScalarEvolution)
98INITIALIZE_PASS_END(BoundsChecking, "bounds-checking",
99 "Run-time bounds checking", false, false)
Nuno Lopes5c525b52012-05-22 17:19:09 +0000100
101
102/// getTrapBB - create a basic block that traps. All overflowing conditions
103/// branch to this block. There's only one trap block per function.
104BasicBlock *BoundsChecking::getTrapBB() {
Nuno Lopes1cbf2be2012-05-31 22:58:48 +0000105 if (TrapBB && !ManyTrapBB)
Nuno Lopes5c525b52012-05-22 17:19:09 +0000106 return TrapBB;
107
108 BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint();
109 TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
110 Builder->SetInsertPoint(TrapBB);
111
112 llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap);
113 CallInst *TrapCall = Builder->CreateCall(F);
114 TrapCall->setDoesNotReturn();
115 TrapCall->setDoesNotThrow();
116 Builder->CreateUnreachable();
117
118 Builder->SetInsertPoint(PrevInsertPoint);
119 return TrapBB;
120}
121
122
Nuno Lopes2b526302012-05-23 16:24:52 +0000123/// emitBranchToTrap - emit a branch instruction to a trap block.
124/// If Cmp is non-null, perform a jump only if its value evaluates to true.
125void BoundsChecking::emitBranchToTrap(Value *Cmp) {
126 Instruction *Inst = Builder->GetInsertPoint();
127 BasicBlock *OldBB = Inst->getParent();
128 BasicBlock *Cont = OldBB->splitBasicBlock(Inst);
129 OldBB->getTerminator()->eraseFromParent();
130
Nuno Lopes2b526302012-05-23 16:24:52 +0000131 if (Cmp)
132 BranchInst::Create(getTrapBB(), Cont, Cmp, OldBB);
133 else
134 BranchInst::Create(getTrapBB(), OldBB);
135}
136
137
Nuno Lopes0463cce2012-05-31 22:45:40 +0000138#define GET_VALUE(Val, Int) \
139 if (!Val) \
140 Val = ConstantInt::get(IntTy, Int)
141
142#define RETURN(Val) \
143 do { ReturnVal = Val; goto cache_and_return; } while (0)
144
145/// computeAllocSize - compute the object size and the offset within the object
146/// pointed by Ptr. OffsetValue/SizeValue will be null if they are constant, and
147/// therefore the result is given in Offset/Size variables instead.
148/// Returns true if the offset and size could be computed within the given
149/// maximum run-time penalty.
150bool BoundsChecking::computeAllocSize(Value *Ptr, APInt &Offset,
151 Value* &OffsetValue, APInt &Size,
152 Value* &SizeValue) {
153 Ptr = Ptr->stripPointerCasts();
154
155 // lookup to see if we've seen the Ptr before
156 CacheMapTy::iterator CacheIt = CacheMap.find(Ptr);
157 if (CacheIt != CacheMap.end()) {
158 CacheData &Cache = CacheIt->second;
159 Offset = Cache.Offset;
160 OffsetValue = Cache.OffsetValue;
161 Size = Cache.Size;
162 SizeValue = Cache.SizeValue;
163 return Cache.ReturnVal;
164 }
165
166 IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
167 unsigned IntTyBits = IntTy->getBitWidth();
168 bool ReturnVal;
169
170 // always generate code immediately before the instruction being processed, so
171 // that the generated code dominates the same BBs
172 Instruction *PrevInsertPoint = Builder->GetInsertPoint();
173 if (Instruction *I = dyn_cast<Instruction>(Ptr))
174 Builder->SetInsertPoint(I);
175
176 // initalize with "don't know" state: offset=0 and size=uintmax
177 Offset = 0;
178 Size = APInt::getMaxValue(TD->getTypeSizeInBits(IntTy));
179 OffsetValue = SizeValue = 0;
180
181 if (GEPOperator *GEP = dyn_cast<GEPOperator>(Ptr)) {
182 APInt PtrOffset(IntTyBits, 0);
183 Value *PtrOffsetValue = 0;
184 if (!computeAllocSize(GEP->getPointerOperand(), PtrOffset, PtrOffsetValue,
185 Size, SizeValue))
186 RETURN(false);
187
188 if (GEP->hasAllConstantIndices()) {
189 SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
190 Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
191 // if PtrOffset is constant, return immediately
192 if (!PtrOffsetValue) {
193 Offset += PtrOffset;
194 RETURN(true);
195 }
196 OffsetValue = ConstantInt::get(IntTy, Offset);
197 } else {
198 OffsetValue = EmitGEPOffset(Builder, *TD, GEP);
199 }
200
201 GET_VALUE(PtrOffsetValue, PtrOffset);
202 OffsetValue = Builder->CreateAdd(PtrOffsetValue, OffsetValue);
203 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000204
205 // global variable with definitive size
Nuno Lopes0463cce2012-05-31 22:45:40 +0000206 } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000207 if (GV->hasDefinitiveInitializer()) {
208 Constant *C = GV->getInitializer();
209 Size = TD->getTypeAllocSize(C->getType());
Nuno Lopes0463cce2012-05-31 22:45:40 +0000210 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000211 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000212 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000213
Nuno Lopes6a06e682012-05-25 16:54:04 +0000214 // stack allocation
Nuno Lopes0463cce2012-05-31 22:45:40 +0000215 } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Ptr)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000216 if (!AI->getAllocatedType()->isSized())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000217 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000218
219 Size = TD->getTypeAllocSize(AI->getAllocatedType());
220 if (!AI->isArrayAllocation())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000221 RETURN(true); // we are done
Nuno Lopes5c525b52012-05-22 17:19:09 +0000222
223 Value *ArraySize = AI->getArraySize();
224 if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000225 Size *= C->getValue();
226 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000227 }
228
229 if (Penalty < 2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000230 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000231
Nuno Lopes0463cce2012-05-31 22:45:40 +0000232 // VLA: compute size dynamically
Nuno Lopes5c525b52012-05-22 17:19:09 +0000233 SizeValue = ConstantInt::get(ArraySize->getType(), Size);
234 SizeValue = Builder->CreateMul(SizeValue, ArraySize);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000235 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000236
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000237 // function arguments
Nuno Lopes0463cce2012-05-31 22:45:40 +0000238 } else if (Argument *A = dyn_cast<Argument>(Ptr)) {
239 // right now we only support byval arguments, so that no interprocedural
240 // analysis is necessary
Nuno Lopes988a0892012-05-29 22:32:51 +0000241 if (!A->hasByValAttr()) {
242 ++ChecksUnableInterproc;
Nuno Lopes0463cce2012-05-31 22:45:40 +0000243 RETURN(false);
Nuno Lopes988a0892012-05-29 22:32:51 +0000244 }
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000245
246 PointerType *PT = cast<PointerType>(A->getType());
247 Size = TD->getTypeAllocSize(PT->getElementType());
Nuno Lopes0463cce2012-05-31 22:45:40 +0000248 RETURN(true);
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000249
Nuno Lopes6a06e682012-05-25 16:54:04 +0000250 // ptr = select(ptr1, ptr2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000251 } else if (SelectInst *SI = dyn_cast<SelectInst>(Ptr)) {
252 APInt OffsetTrue(IntTyBits, 0), OffsetFalse(IntTyBits, 0);
253 APInt SizeTrue(IntTyBits, 0), SizeFalse(IntTyBits, 0);
254 Value *OffsetValueTrue = 0, *OffsetValueFalse = 0;
255 Value *SizeValueTrue = 0, *SizeValueFalse = 0;
Nuno Lopes6a06e682012-05-25 16:54:04 +0000256
Nuno Lopes0463cce2012-05-31 22:45:40 +0000257 bool TrueAlloc = computeAllocSize(SI->getTrueValue(), OffsetTrue,
258 OffsetValueTrue, SizeTrue, SizeValueTrue);
259 bool FalseAlloc = computeAllocSize(SI->getFalseValue(), OffsetFalse,
260 OffsetValueFalse, SizeFalse,
261 SizeValueFalse);
262 if (!TrueAlloc && !FalseAlloc)
263 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000264
Nuno Lopes0463cce2012-05-31 22:45:40 +0000265 // fold constant sizes & offsets if they are equal
266 if (!OffsetValueTrue && !OffsetValueFalse && OffsetTrue == OffsetFalse)
267 Offset = OffsetTrue;
268 else if (Penalty > 1) {
269 GET_VALUE(OffsetValueTrue, OffsetTrue);
270 GET_VALUE(OffsetValueFalse, OffsetFalse);
271 OffsetValue = Builder->CreateSelect(SI->getCondition(), OffsetValueTrue,
272 OffsetValueFalse);
273 } else
274 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000275
Nuno Lopes0463cce2012-05-31 22:45:40 +0000276 if (!SizeValueTrue && !SizeValueFalse && SizeTrue == SizeFalse)
277 Size = SizeTrue;
278 else if (Penalty > 1) {
279 GET_VALUE(SizeValueTrue, SizeTrue);
280 GET_VALUE(SizeValueFalse, SizeFalse);
281 SizeValue = Builder->CreateSelect(SI->getCondition(), SizeValueTrue,
282 SizeValueFalse);
283 } else
284 RETURN(false);
285 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000286
287 // call allocation function
Nuno Lopes0463cce2012-05-31 22:45:40 +0000288 } else if (CallInst *CI = dyn_cast<CallInst>(Ptr)) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000289 SmallVector<unsigned, 4> Args;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000290
Nuno Lopes6a06e682012-05-25 16:54:04 +0000291 if (MDNode *MD = CI->getMetadata("alloc_size")) {
292 for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i)
293 Args.push_back(cast<ConstantInt>(MD->getOperand(i))->getZExtValue());
294
295 } else if (Function *Callee = CI->getCalledFunction()) {
296 FunctionType *FTy = Callee->getFunctionType();
297
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000298 // alloc(size)
Nuno Lopes6a06e682012-05-25 16:54:04 +0000299 if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy()) {
300 if ((Callee->getName() == "malloc" ||
301 Callee->getName() == "valloc" ||
302 Callee->getName() == "_Znwj" || // operator new(unsigned int)
303 Callee->getName() == "_Znwm" || // operator new(unsigned long)
304 Callee->getName() == "_Znaj" || // operator new[](unsigned int)
305 Callee->getName() == "_Znam")) {
306 Args.push_back(0);
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000307 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000308 } else if (FTy->getNumParams() == 2) {
309 // alloc(_, x)
310 if (FTy->getParamType(1)->isIntegerTy() &&
311 ((Callee->getName() == "realloc" ||
312 Callee->getName() == "reallocf"))) {
313 Args.push_back(1);
314
315 // alloc(x, y)
316 } else if (FTy->getParamType(0)->isIntegerTy() &&
317 FTy->getParamType(1)->isIntegerTy() &&
318 Callee->getName() == "calloc") {
319 Args.push_back(0);
320 Args.push_back(1);
321 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000322 } else if (FTy->getNumParams() == 3) {
323 // alloc(_, _, x)
324 if (FTy->getParamType(2)->isIntegerTy() &&
325 Callee->getName() == "posix_memalign") {
326 Args.push_back(2);
327 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000328 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000329 }
330
331 if (Args.empty())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000332 RETURN(false);
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000333
Nuno Lopes6a06e682012-05-25 16:54:04 +0000334 // check if all arguments are constant. if so, the object size is also const
335 bool AllConst = true;
336 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
337 I != E; ++I) {
338 if (!isa<ConstantInt>(CI->getArgOperand(*I))) {
339 AllConst = false;
340 break;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000341 }
342 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000343
344 if (AllConst) {
345 Size = 1;
346 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
347 I != E; ++I) {
348 ConstantInt *Arg = cast<ConstantInt>(CI->getArgOperand(*I));
Nuno Lopes0463cce2012-05-31 22:45:40 +0000349 Size *= Arg->getValue().zextOrSelf(IntTyBits);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000350 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000351 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000352 }
353
354 if (Penalty < 2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000355 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000356
357 // not all arguments are constant, so create a sequence of multiplications
Nuno Lopes6a06e682012-05-25 16:54:04 +0000358 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
359 I != E; ++I) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000360 Value *Arg = Builder->CreateZExt(CI->getArgOperand(*I), IntTy);
361 if (!SizeValue) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000362 SizeValue = Arg;
Nuno Lopes6a06e682012-05-25 16:54:04 +0000363 continue;
364 }
365 SizeValue = Builder->CreateMul(SizeValue, Arg);
366 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000367 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000368
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000369 // TODO: handle more standard functions:
370 // - strdup / strndup
371 // - strcpy / strncpy
372 // - memcpy / memmove
373 // - strcat / strncat
Nuno Lopes988a0892012-05-29 22:32:51 +0000374
Nuno Lopes0463cce2012-05-31 22:45:40 +0000375 } else if (PHINode *PHI = dyn_cast<PHINode>(Ptr)) {
376 // create 2 PHIs: one for offset and another for size
377 PHINode *OffsetPHI = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
378 PHINode *SizePHI = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
379
380 // insert right away in the cache to handle recursive PHIs
381 CacheData CacheEntry;
382 CacheEntry.Offset = CacheEntry.Size = 0;
383 CacheEntry.OffsetValue = OffsetPHI;
384 CacheEntry.SizeValue = SizePHI;
385 CacheEntry.ReturnVal = true;
386 CacheMap[Ptr] = CacheEntry;
387
388 // compute offset/size for each PHI incoming pointer
389 bool someOk = false;
390 for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) {
391 Builder->SetInsertPoint(PHI->getIncomingBlock(i)->getFirstInsertionPt());
392
393 APInt PhiOffset(IntTyBits, 0), PhiSize(IntTyBits, 0);
394 Value *PhiOffsetValue = 0, *PhiSizeValue = 0;
395 someOk |= computeAllocSize(PHI->getIncomingValue(i), PhiOffset,
396 PhiOffsetValue, PhiSize, PhiSizeValue);
397
398 GET_VALUE(PhiOffsetValue, PhiOffset);
399 GET_VALUE(PhiSizeValue, PhiSize);
400
401 OffsetPHI->addIncoming(PhiOffsetValue, PHI->getIncomingBlock(i));
402 SizePHI->addIncoming(PhiSizeValue, PHI->getIncomingBlock(i));
403 }
404
405 // fail here if we couldn't compute the size/offset in any incoming edge
406 if (!someOk)
407 RETURN(false);
408
409 OffsetValue = OffsetPHI;
410 SizeValue = SizePHI;
411 RETURN(true);
412
413 } else if (isa<UndefValue>(Ptr)) {
414 Size = 0;
415 RETURN(true);
416
417 } else if (isa<LoadInst>(Ptr)) {
Nuno Lopes988a0892012-05-29 22:32:51 +0000418 ++ChecksUnableLoad;
Nuno Lopes0463cce2012-05-31 22:45:40 +0000419 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000420 }
421
Nuno Lopes0463cce2012-05-31 22:45:40 +0000422 RETURN(false);
423
424cache_and_return:
425 // cache the result and return
426 CacheData CacheEntry;
427 CacheEntry.Offset = Offset;
428 CacheEntry.OffsetValue = OffsetValue;
429 CacheEntry.Size = Size;
430 CacheEntry.SizeValue = SizeValue;
431 CacheEntry.ReturnVal = ReturnVal;
432 CacheMap[Ptr] = CacheEntry;
433
434 Builder->SetInsertPoint(PrevInsertPoint);
435 return ReturnVal;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000436}
437
438
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000439/// instrument - adds run-time bounds checks to memory accessing instructions.
440/// Ptr is the pointer that will be read/written, and InstVal is either the
441/// result from the load or the value being stored. It is used to determine the
442/// size of memory block that is touched.
443/// Returns true if any change was made to the IR, false otherwise.
Nuno Lopes5c525b52012-05-22 17:19:09 +0000444bool BoundsChecking::instrument(Value *Ptr, Value *InstVal) {
445 uint64_t NeededSize = TD->getTypeStoreSize(InstVal->getType());
446 DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize)
447 << " bytes\n");
448
Nuno Lopes0463cce2012-05-31 22:45:40 +0000449 IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
450 unsigned IntTyBits = IntTy->getBitWidth();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000451
Nuno Lopes0463cce2012-05-31 22:45:40 +0000452 APInt Offset(IntTyBits, 0), Size(IntTyBits, 0);
453 Value *OffsetValue = 0, *SizeValue = 0;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000454
Nuno Lopes0463cce2012-05-31 22:45:40 +0000455 if (!computeAllocSize(Ptr, Offset, OffsetValue, Size, SizeValue)) {
Nuno Lopes988a0892012-05-29 22:32:51 +0000456 DEBUG(dbgs() << "computeAllocSize failed:\n" << *Ptr << "\n");
Nuno Lopes5c525b52012-05-22 17:19:09 +0000457 ++ChecksUnable;
458 return false;
459 }
Nuno Lopes5c525b52012-05-22 17:19:09 +0000460
Nuno Lopes0463cce2012-05-31 22:45:40 +0000461 // three checks are required to ensure safety:
462 // . Offset >= 0 (since the offset is given from the base ptr)
463 // . Size >= Offset (unsigned)
464 // . Size - Offset >= NeededSize (unsigned)
465 if (!OffsetValue && !SizeValue) {
466 if (Offset.slt(0) || Size.ult(Offset) || (Size - Offset).ult(NeededSize)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000467 // Out of bounds
Nuno Lopes2b526302012-05-23 16:24:52 +0000468 emitBranchToTrap();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000469 ++ChecksAdded;
470 return true;
471 }
472 // in bounds
473 ++ChecksSkipped;
474 return false;
475 }
476
Nuno Lopes0463cce2012-05-31 22:45:40 +0000477 // emit check for offset < 0
478 Value *CmpOffset = 0;
479 if (OffsetValue)
480 CmpOffset = Builder->CreateICmpSLT(OffsetValue, ConstantInt::get(IntTy, 0));
481 else if (Offset.slt(0)) {
482 // offset proved to be negative
483 emitBranchToTrap();
484 ++ChecksAdded;
485 return true;
486 }
Nuno Lopes5c525b52012-05-22 17:19:09 +0000487
Nuno Lopes0463cce2012-05-31 22:45:40 +0000488 // we couldn't determine statically if the memory access is safe; emit a
489 // run-time check
490 GET_VALUE(OffsetValue, Offset);
491 GET_VALUE(SizeValue, Size);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000492
Nuno Lopes0463cce2012-05-31 22:45:40 +0000493 Value *NeededSizeVal = ConstantInt::get(IntTy, NeededSize);
494 // FIXME: add NSW/NUW here? -- we dont care if the subtraction overflows
Nuno Lopes5c525b52012-05-22 17:19:09 +0000495 Value *ObjSize = Builder->CreateSub(SizeValue, OffsetValue);
496 Value *Cmp1 = Builder->CreateICmpULT(SizeValue, OffsetValue);
497 Value *Cmp2 = Builder->CreateICmpULT(ObjSize, NeededSizeVal);
498 Value *Or = Builder->CreateOr(Cmp1, Cmp2);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000499 if (CmpOffset)
500 Or = Builder->CreateOr(CmpOffset, Or);
Nuno Lopes2b526302012-05-23 16:24:52 +0000501 emitBranchToTrap(Or);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000502
Nuno Lopes5c525b52012-05-22 17:19:09 +0000503 ++ChecksAdded;
504 return true;
505}
506
507bool BoundsChecking::runOnFunction(Function &F) {
508 TD = &getAnalysis<TargetData>();
Nuno Lopes988a0892012-05-29 22:32:51 +0000509 LI = &getAnalysis<LoopInfo>();
510 SE = &getAnalysis<ScalarEvolution>();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000511
512 TrapBB = 0;
513 Fn = &F;
514 BuilderTy TheBuilder(F.getContext(), TargetFolder(TD));
515 Builder = &TheBuilder;
516
517 // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory
518 // touching instructions
519 std::vector<Instruction*> WorkList;
520 for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
521 Instruction *I = &*i;
522 if (isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) ||
523 isa<AtomicRMWInst>(I))
524 WorkList.push_back(I);
525 }
526
527 bool MadeChange = false;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000528 for (std::vector<Instruction*>::iterator i = WorkList.begin(),
529 e = WorkList.end(); i != e; ++i) {
530 Instruction *I = *i;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000531
532 Builder->SetInsertPoint(I);
533 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
534 MadeChange |= instrument(LI->getPointerOperand(), LI);
535 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
536 MadeChange |= instrument(SI->getPointerOperand(), SI->getValueOperand());
537 } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(I)) {
538 MadeChange |= instrument(AI->getPointerOperand(),AI->getCompareOperand());
539 } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(I)) {
540 MadeChange |= instrument(AI->getPointerOperand(), AI->getValOperand());
541 } else {
542 llvm_unreachable("unknown Instruction type");
543 }
544 }
545 return MadeChange;
546}
547
548FunctionPass *llvm::createBoundsCheckingPass(unsigned Penalty) {
549 return new BoundsChecking(Penalty);
550}