blob: 738b1f27bdb78fb3b06ca1f5c5badebf0dafdcb5 [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 Lopes5c525b52012-05-22 17:19:09 +000023#include "llvm/Support/Debug.h"
24#include "llvm/Support/InstIterator.h"
25#include "llvm/Support/IRBuilder.h"
Nuno Lopes2f0a7482012-05-22 22:02:19 +000026#include "llvm/Support/raw_ostream.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000027#include "llvm/Support/TargetFolder.h"
28#include "llvm/Target/TargetData.h"
29#include "llvm/Transforms/Utils/Local.h"
30#include "llvm/GlobalVariable.h"
31#include "llvm/Instructions.h"
32#include "llvm/Intrinsics.h"
Nuno Lopes6a06e682012-05-25 16:54:04 +000033#include "llvm/Metadata.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000034#include "llvm/Operator.h"
35#include "llvm/Pass.h"
36using namespace llvm;
37
38STATISTIC(ChecksAdded, "Bounds checks added");
39STATISTIC(ChecksSkipped, "Bounds checks skipped");
40STATISTIC(ChecksUnable, "Bounds checks unable to add");
Nuno Lopes988a0892012-05-29 22:32:51 +000041STATISTIC(ChecksUnableInterproc, "Bounds checks unable to add (interprocedural)");
42STATISTIC(ChecksUnableLoad, "Bounds checks unable to add (LoadInst)");
Nuno Lopes5c525b52012-05-22 17:19:09 +000043
44typedef IRBuilder<true, TargetFolder> BuilderTy;
45
46namespace {
Nuno Lopes0463cce2012-05-31 22:45:40 +000047 // FIXME: can use unions here to save space
48 struct CacheData {
49 APInt Offset;
50 Value *OffsetValue;
51 APInt Size;
52 Value *SizeValue;
53 bool ReturnVal;
Nuno Lopes5c525b52012-05-22 17:19:09 +000054 };
Nuno Lopes0463cce2012-05-31 22:45:40 +000055 typedef DenseMap<Value*, CacheData> CacheMapTy;
Nuno Lopes5c525b52012-05-22 17:19:09 +000056
57 struct BoundsChecking : public FunctionPass {
Nuno Lopes5c525b52012-05-22 17:19:09 +000058 static char ID;
59
60 BoundsChecking(unsigned _Penalty = 5) : FunctionPass(ID), Penalty(_Penalty){
61 initializeBoundsCheckingPass(*PassRegistry::getPassRegistry());
62 }
63
Nuno Lopes5c525b52012-05-22 17:19:09 +000064 virtual bool runOnFunction(Function &F);
65
66 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
67 AU.addRequired<TargetData>();
Nuno Lopes988a0892012-05-29 22:32:51 +000068 AU.addRequired<LoopInfo>();
69 AU.addRequired<ScalarEvolution>();
Nuno Lopes5c525b52012-05-22 17:19:09 +000070 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +000071
72 private:
73 const TargetData *TD;
Nuno Lopes988a0892012-05-29 22:32:51 +000074 LoopInfo *LI;
75 ScalarEvolution *SE;
Nuno Lopes2f0a7482012-05-22 22:02:19 +000076 BuilderTy *Builder;
77 Function *Fn;
78 BasicBlock *TrapBB;
79 unsigned Penalty;
Nuno Lopes0463cce2012-05-31 22:45:40 +000080 CacheMapTy CacheMap;
Nuno Lopes2f0a7482012-05-22 22:02:19 +000081
82 BasicBlock *getTrapBB();
Nuno Lopes2b526302012-05-23 16:24:52 +000083 void emitBranchToTrap(Value *Cmp = 0);
Nuno Lopes0463cce2012-05-31 22:45:40 +000084 bool computeAllocSize(Value *Ptr, APInt &Offset, Value* &OffsetValue,
85 APInt &Size, Value* &SizeValue);
Nuno Lopes2f0a7482012-05-22 22:02:19 +000086 bool instrument(Value *Ptr, Value *Val);
Nuno Lopes5c525b52012-05-22 17:19:09 +000087 };
88}
89
90char BoundsChecking::ID = 0;
Nuno Lopes988a0892012-05-29 22:32:51 +000091INITIALIZE_PASS_BEGIN(BoundsChecking, "bounds-checking",
92 "Run-time bounds checking", false, false)
93INITIALIZE_PASS_DEPENDENCY(ScalarEvolution)
94INITIALIZE_PASS_END(BoundsChecking, "bounds-checking",
95 "Run-time bounds checking", false, false)
Nuno Lopes5c525b52012-05-22 17:19:09 +000096
97
98/// getTrapBB - create a basic block that traps. All overflowing conditions
99/// branch to this block. There's only one trap block per function.
100BasicBlock *BoundsChecking::getTrapBB() {
101 if (TrapBB)
102 return TrapBB;
103
104 BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint();
105 TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
106 Builder->SetInsertPoint(TrapBB);
107
108 llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap);
109 CallInst *TrapCall = Builder->CreateCall(F);
110 TrapCall->setDoesNotReturn();
111 TrapCall->setDoesNotThrow();
112 Builder->CreateUnreachable();
113
114 Builder->SetInsertPoint(PrevInsertPoint);
115 return TrapBB;
116}
117
118
Nuno Lopes2b526302012-05-23 16:24:52 +0000119/// emitBranchToTrap - emit a branch instruction to a trap block.
120/// If Cmp is non-null, perform a jump only if its value evaluates to true.
121void BoundsChecking::emitBranchToTrap(Value *Cmp) {
122 Instruction *Inst = Builder->GetInsertPoint();
123 BasicBlock *OldBB = Inst->getParent();
124 BasicBlock *Cont = OldBB->splitBasicBlock(Inst);
125 OldBB->getTerminator()->eraseFromParent();
126
Nuno Lopes2b526302012-05-23 16:24:52 +0000127 if (Cmp)
128 BranchInst::Create(getTrapBB(), Cont, Cmp, OldBB);
129 else
130 BranchInst::Create(getTrapBB(), OldBB);
131}
132
133
Nuno Lopes0463cce2012-05-31 22:45:40 +0000134#define GET_VALUE(Val, Int) \
135 if (!Val) \
136 Val = ConstantInt::get(IntTy, Int)
137
138#define RETURN(Val) \
139 do { ReturnVal = Val; goto cache_and_return; } while (0)
140
141/// computeAllocSize - compute the object size and the offset within the object
142/// pointed by Ptr. OffsetValue/SizeValue will be null if they are constant, and
143/// therefore the result is given in Offset/Size variables instead.
144/// Returns true if the offset and size could be computed within the given
145/// maximum run-time penalty.
146bool BoundsChecking::computeAllocSize(Value *Ptr, APInt &Offset,
147 Value* &OffsetValue, APInt &Size,
148 Value* &SizeValue) {
149 Ptr = Ptr->stripPointerCasts();
150
151 // lookup to see if we've seen the Ptr before
152 CacheMapTy::iterator CacheIt = CacheMap.find(Ptr);
153 if (CacheIt != CacheMap.end()) {
154 CacheData &Cache = CacheIt->second;
155 Offset = Cache.Offset;
156 OffsetValue = Cache.OffsetValue;
157 Size = Cache.Size;
158 SizeValue = Cache.SizeValue;
159 return Cache.ReturnVal;
160 }
161
162 IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
163 unsigned IntTyBits = IntTy->getBitWidth();
164 bool ReturnVal;
165
166 // always generate code immediately before the instruction being processed, so
167 // that the generated code dominates the same BBs
168 Instruction *PrevInsertPoint = Builder->GetInsertPoint();
169 if (Instruction *I = dyn_cast<Instruction>(Ptr))
170 Builder->SetInsertPoint(I);
171
172 // initalize with "don't know" state: offset=0 and size=uintmax
173 Offset = 0;
174 Size = APInt::getMaxValue(TD->getTypeSizeInBits(IntTy));
175 OffsetValue = SizeValue = 0;
176
177 if (GEPOperator *GEP = dyn_cast<GEPOperator>(Ptr)) {
178 APInt PtrOffset(IntTyBits, 0);
179 Value *PtrOffsetValue = 0;
180 if (!computeAllocSize(GEP->getPointerOperand(), PtrOffset, PtrOffsetValue,
181 Size, SizeValue))
182 RETURN(false);
183
184 if (GEP->hasAllConstantIndices()) {
185 SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
186 Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
187 // if PtrOffset is constant, return immediately
188 if (!PtrOffsetValue) {
189 Offset += PtrOffset;
190 RETURN(true);
191 }
192 OffsetValue = ConstantInt::get(IntTy, Offset);
193 } else {
194 OffsetValue = EmitGEPOffset(Builder, *TD, GEP);
195 }
196
197 GET_VALUE(PtrOffsetValue, PtrOffset);
198 OffsetValue = Builder->CreateAdd(PtrOffsetValue, OffsetValue);
199 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000200
201 // global variable with definitive size
Nuno Lopes0463cce2012-05-31 22:45:40 +0000202 } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000203 if (GV->hasDefinitiveInitializer()) {
204 Constant *C = GV->getInitializer();
205 Size = TD->getTypeAllocSize(C->getType());
Nuno Lopes0463cce2012-05-31 22:45:40 +0000206 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000207 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000208 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000209
Nuno Lopes6a06e682012-05-25 16:54:04 +0000210 // stack allocation
Nuno Lopes0463cce2012-05-31 22:45:40 +0000211 } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Ptr)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000212 if (!AI->getAllocatedType()->isSized())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000213 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000214
215 Size = TD->getTypeAllocSize(AI->getAllocatedType());
216 if (!AI->isArrayAllocation())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000217 RETURN(true); // we are done
Nuno Lopes5c525b52012-05-22 17:19:09 +0000218
219 Value *ArraySize = AI->getArraySize();
220 if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000221 Size *= C->getValue();
222 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000223 }
224
225 if (Penalty < 2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000226 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000227
Nuno Lopes0463cce2012-05-31 22:45:40 +0000228 // VLA: compute size dynamically
Nuno Lopes5c525b52012-05-22 17:19:09 +0000229 SizeValue = ConstantInt::get(ArraySize->getType(), Size);
230 SizeValue = Builder->CreateMul(SizeValue, ArraySize);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000231 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000232
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000233 // function arguments
Nuno Lopes0463cce2012-05-31 22:45:40 +0000234 } else if (Argument *A = dyn_cast<Argument>(Ptr)) {
235 // right now we only support byval arguments, so that no interprocedural
236 // analysis is necessary
Nuno Lopes988a0892012-05-29 22:32:51 +0000237 if (!A->hasByValAttr()) {
238 ++ChecksUnableInterproc;
Nuno Lopes0463cce2012-05-31 22:45:40 +0000239 RETURN(false);
Nuno Lopes988a0892012-05-29 22:32:51 +0000240 }
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000241
242 PointerType *PT = cast<PointerType>(A->getType());
243 Size = TD->getTypeAllocSize(PT->getElementType());
Nuno Lopes0463cce2012-05-31 22:45:40 +0000244 RETURN(true);
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000245
Nuno Lopes6a06e682012-05-25 16:54:04 +0000246 // ptr = select(ptr1, ptr2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000247 } else if (SelectInst *SI = dyn_cast<SelectInst>(Ptr)) {
248 APInt OffsetTrue(IntTyBits, 0), OffsetFalse(IntTyBits, 0);
249 APInt SizeTrue(IntTyBits, 0), SizeFalse(IntTyBits, 0);
250 Value *OffsetValueTrue = 0, *OffsetValueFalse = 0;
251 Value *SizeValueTrue = 0, *SizeValueFalse = 0;
Nuno Lopes6a06e682012-05-25 16:54:04 +0000252
Nuno Lopes0463cce2012-05-31 22:45:40 +0000253 bool TrueAlloc = computeAllocSize(SI->getTrueValue(), OffsetTrue,
254 OffsetValueTrue, SizeTrue, SizeValueTrue);
255 bool FalseAlloc = computeAllocSize(SI->getFalseValue(), OffsetFalse,
256 OffsetValueFalse, SizeFalse,
257 SizeValueFalse);
258 if (!TrueAlloc && !FalseAlloc)
259 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000260
Nuno Lopes0463cce2012-05-31 22:45:40 +0000261 // fold constant sizes & offsets if they are equal
262 if (!OffsetValueTrue && !OffsetValueFalse && OffsetTrue == OffsetFalse)
263 Offset = OffsetTrue;
264 else if (Penalty > 1) {
265 GET_VALUE(OffsetValueTrue, OffsetTrue);
266 GET_VALUE(OffsetValueFalse, OffsetFalse);
267 OffsetValue = Builder->CreateSelect(SI->getCondition(), OffsetValueTrue,
268 OffsetValueFalse);
269 } else
270 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000271
Nuno Lopes0463cce2012-05-31 22:45:40 +0000272 if (!SizeValueTrue && !SizeValueFalse && SizeTrue == SizeFalse)
273 Size = SizeTrue;
274 else if (Penalty > 1) {
275 GET_VALUE(SizeValueTrue, SizeTrue);
276 GET_VALUE(SizeValueFalse, SizeFalse);
277 SizeValue = Builder->CreateSelect(SI->getCondition(), SizeValueTrue,
278 SizeValueFalse);
279 } else
280 RETURN(false);
281 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000282
283 // call allocation function
Nuno Lopes0463cce2012-05-31 22:45:40 +0000284 } else if (CallInst *CI = dyn_cast<CallInst>(Ptr)) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000285 SmallVector<unsigned, 4> Args;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000286
Nuno Lopes6a06e682012-05-25 16:54:04 +0000287 if (MDNode *MD = CI->getMetadata("alloc_size")) {
288 for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i)
289 Args.push_back(cast<ConstantInt>(MD->getOperand(i))->getZExtValue());
290
291 } else if (Function *Callee = CI->getCalledFunction()) {
292 FunctionType *FTy = Callee->getFunctionType();
293
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000294 // alloc(size)
Nuno Lopes6a06e682012-05-25 16:54:04 +0000295 if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy()) {
296 if ((Callee->getName() == "malloc" ||
297 Callee->getName() == "valloc" ||
298 Callee->getName() == "_Znwj" || // operator new(unsigned int)
299 Callee->getName() == "_Znwm" || // operator new(unsigned long)
300 Callee->getName() == "_Znaj" || // operator new[](unsigned int)
301 Callee->getName() == "_Znam")) {
302 Args.push_back(0);
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000303 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000304 } else if (FTy->getNumParams() == 2) {
305 // alloc(_, x)
306 if (FTy->getParamType(1)->isIntegerTy() &&
307 ((Callee->getName() == "realloc" ||
308 Callee->getName() == "reallocf"))) {
309 Args.push_back(1);
310
311 // alloc(x, y)
312 } else if (FTy->getParamType(0)->isIntegerTy() &&
313 FTy->getParamType(1)->isIntegerTy() &&
314 Callee->getName() == "calloc") {
315 Args.push_back(0);
316 Args.push_back(1);
317 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000318 } else if (FTy->getNumParams() == 3) {
319 // alloc(_, _, x)
320 if (FTy->getParamType(2)->isIntegerTy() &&
321 Callee->getName() == "posix_memalign") {
322 Args.push_back(2);
323 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000324 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000325 }
326
327 if (Args.empty())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000328 RETURN(false);
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000329
Nuno Lopes6a06e682012-05-25 16:54:04 +0000330 // check if all arguments are constant. if so, the object size is also const
331 bool AllConst = true;
332 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
333 I != E; ++I) {
334 if (!isa<ConstantInt>(CI->getArgOperand(*I))) {
335 AllConst = false;
336 break;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000337 }
338 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000339
340 if (AllConst) {
341 Size = 1;
342 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
343 I != E; ++I) {
344 ConstantInt *Arg = cast<ConstantInt>(CI->getArgOperand(*I));
Nuno Lopes0463cce2012-05-31 22:45:40 +0000345 Size *= Arg->getValue().zextOrSelf(IntTyBits);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000346 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000347 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000348 }
349
350 if (Penalty < 2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000351 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000352
353 // not all arguments are constant, so create a sequence of multiplications
Nuno Lopes6a06e682012-05-25 16:54:04 +0000354 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
355 I != E; ++I) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000356 Value *Arg = Builder->CreateZExt(CI->getArgOperand(*I), IntTy);
357 if (!SizeValue) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000358 SizeValue = Arg;
Nuno Lopes6a06e682012-05-25 16:54:04 +0000359 continue;
360 }
361 SizeValue = Builder->CreateMul(SizeValue, Arg);
362 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000363 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000364
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000365 // TODO: handle more standard functions:
366 // - strdup / strndup
367 // - strcpy / strncpy
368 // - memcpy / memmove
369 // - strcat / strncat
Nuno Lopes988a0892012-05-29 22:32:51 +0000370
Nuno Lopes0463cce2012-05-31 22:45:40 +0000371 } else if (PHINode *PHI = dyn_cast<PHINode>(Ptr)) {
372 // create 2 PHIs: one for offset and another for size
373 PHINode *OffsetPHI = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
374 PHINode *SizePHI = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
375
376 // insert right away in the cache to handle recursive PHIs
377 CacheData CacheEntry;
378 CacheEntry.Offset = CacheEntry.Size = 0;
379 CacheEntry.OffsetValue = OffsetPHI;
380 CacheEntry.SizeValue = SizePHI;
381 CacheEntry.ReturnVal = true;
382 CacheMap[Ptr] = CacheEntry;
383
384 // compute offset/size for each PHI incoming pointer
385 bool someOk = false;
386 for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) {
387 Builder->SetInsertPoint(PHI->getIncomingBlock(i)->getFirstInsertionPt());
388
389 APInt PhiOffset(IntTyBits, 0), PhiSize(IntTyBits, 0);
390 Value *PhiOffsetValue = 0, *PhiSizeValue = 0;
391 someOk |= computeAllocSize(PHI->getIncomingValue(i), PhiOffset,
392 PhiOffsetValue, PhiSize, PhiSizeValue);
393
394 GET_VALUE(PhiOffsetValue, PhiOffset);
395 GET_VALUE(PhiSizeValue, PhiSize);
396
397 OffsetPHI->addIncoming(PhiOffsetValue, PHI->getIncomingBlock(i));
398 SizePHI->addIncoming(PhiSizeValue, PHI->getIncomingBlock(i));
399 }
400
401 // fail here if we couldn't compute the size/offset in any incoming edge
402 if (!someOk)
403 RETURN(false);
404
405 OffsetValue = OffsetPHI;
406 SizeValue = SizePHI;
407 RETURN(true);
408
409 } else if (isa<UndefValue>(Ptr)) {
410 Size = 0;
411 RETURN(true);
412
413 } else if (isa<LoadInst>(Ptr)) {
Nuno Lopes988a0892012-05-29 22:32:51 +0000414 ++ChecksUnableLoad;
Nuno Lopes0463cce2012-05-31 22:45:40 +0000415 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000416 }
417
Nuno Lopes0463cce2012-05-31 22:45:40 +0000418 RETURN(false);
419
420cache_and_return:
421 // cache the result and return
422 CacheData CacheEntry;
423 CacheEntry.Offset = Offset;
424 CacheEntry.OffsetValue = OffsetValue;
425 CacheEntry.Size = Size;
426 CacheEntry.SizeValue = SizeValue;
427 CacheEntry.ReturnVal = ReturnVal;
428 CacheMap[Ptr] = CacheEntry;
429
430 Builder->SetInsertPoint(PrevInsertPoint);
431 return ReturnVal;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000432}
433
434
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000435/// instrument - adds run-time bounds checks to memory accessing instructions.
436/// Ptr is the pointer that will be read/written, and InstVal is either the
437/// result from the load or the value being stored. It is used to determine the
438/// size of memory block that is touched.
439/// Returns true if any change was made to the IR, false otherwise.
Nuno Lopes5c525b52012-05-22 17:19:09 +0000440bool BoundsChecking::instrument(Value *Ptr, Value *InstVal) {
441 uint64_t NeededSize = TD->getTypeStoreSize(InstVal->getType());
442 DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize)
443 << " bytes\n");
444
Nuno Lopes0463cce2012-05-31 22:45:40 +0000445 IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
446 unsigned IntTyBits = IntTy->getBitWidth();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000447
Nuno Lopes0463cce2012-05-31 22:45:40 +0000448 APInt Offset(IntTyBits, 0), Size(IntTyBits, 0);
449 Value *OffsetValue = 0, *SizeValue = 0;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000450
Nuno Lopes0463cce2012-05-31 22:45:40 +0000451 if (!computeAllocSize(Ptr, Offset, OffsetValue, Size, SizeValue)) {
Nuno Lopes988a0892012-05-29 22:32:51 +0000452 DEBUG(dbgs() << "computeAllocSize failed:\n" << *Ptr << "\n");
Nuno Lopes5c525b52012-05-22 17:19:09 +0000453 ++ChecksUnable;
454 return false;
455 }
Nuno Lopes5c525b52012-05-22 17:19:09 +0000456
Nuno Lopes0463cce2012-05-31 22:45:40 +0000457 // three checks are required to ensure safety:
458 // . Offset >= 0 (since the offset is given from the base ptr)
459 // . Size >= Offset (unsigned)
460 // . Size - Offset >= NeededSize (unsigned)
461 if (!OffsetValue && !SizeValue) {
462 if (Offset.slt(0) || Size.ult(Offset) || (Size - Offset).ult(NeededSize)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000463 // Out of bounds
Nuno Lopes2b526302012-05-23 16:24:52 +0000464 emitBranchToTrap();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000465 ++ChecksAdded;
466 return true;
467 }
468 // in bounds
469 ++ChecksSkipped;
470 return false;
471 }
472
Nuno Lopes0463cce2012-05-31 22:45:40 +0000473 // emit check for offset < 0
474 Value *CmpOffset = 0;
475 if (OffsetValue)
476 CmpOffset = Builder->CreateICmpSLT(OffsetValue, ConstantInt::get(IntTy, 0));
477 else if (Offset.slt(0)) {
478 // offset proved to be negative
479 emitBranchToTrap();
480 ++ChecksAdded;
481 return true;
482 }
Nuno Lopes5c525b52012-05-22 17:19:09 +0000483
Nuno Lopes0463cce2012-05-31 22:45:40 +0000484 // we couldn't determine statically if the memory access is safe; emit a
485 // run-time check
486 GET_VALUE(OffsetValue, Offset);
487 GET_VALUE(SizeValue, Size);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000488
Nuno Lopes0463cce2012-05-31 22:45:40 +0000489 Value *NeededSizeVal = ConstantInt::get(IntTy, NeededSize);
490 // FIXME: add NSW/NUW here? -- we dont care if the subtraction overflows
Nuno Lopes5c525b52012-05-22 17:19:09 +0000491 Value *ObjSize = Builder->CreateSub(SizeValue, OffsetValue);
492 Value *Cmp1 = Builder->CreateICmpULT(SizeValue, OffsetValue);
493 Value *Cmp2 = Builder->CreateICmpULT(ObjSize, NeededSizeVal);
494 Value *Or = Builder->CreateOr(Cmp1, Cmp2);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000495 if (CmpOffset)
496 Or = Builder->CreateOr(CmpOffset, Or);
Nuno Lopes2b526302012-05-23 16:24:52 +0000497 emitBranchToTrap(Or);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000498
Nuno Lopes5c525b52012-05-22 17:19:09 +0000499 ++ChecksAdded;
500 return true;
501}
502
503bool BoundsChecking::runOnFunction(Function &F) {
504 TD = &getAnalysis<TargetData>();
Nuno Lopes988a0892012-05-29 22:32:51 +0000505 LI = &getAnalysis<LoopInfo>();
506 SE = &getAnalysis<ScalarEvolution>();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000507
508 TrapBB = 0;
509 Fn = &F;
510 BuilderTy TheBuilder(F.getContext(), TargetFolder(TD));
511 Builder = &TheBuilder;
512
513 // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory
514 // touching instructions
515 std::vector<Instruction*> WorkList;
516 for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
517 Instruction *I = &*i;
518 if (isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) ||
519 isa<AtomicRMWInst>(I))
520 WorkList.push_back(I);
521 }
522
523 bool MadeChange = false;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000524 for (std::vector<Instruction*>::iterator i = WorkList.begin(),
525 e = WorkList.end(); i != e; ++i) {
526 Instruction *I = *i;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000527
528 Builder->SetInsertPoint(I);
529 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
530 MadeChange |= instrument(LI->getPointerOperand(), LI);
531 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
532 MadeChange |= instrument(SI->getPointerOperand(), SI->getValueOperand());
533 } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(I)) {
534 MadeChange |= instrument(AI->getPointerOperand(),AI->getCompareOperand());
535 } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(I)) {
536 MadeChange |= instrument(AI->getPointerOperand(), AI->getValOperand());
537 } else {
538 llvm_unreachable("unknown Instruction type");
539 }
540 }
541 return MadeChange;
542}
543
544FunctionPass *llvm::createBoundsCheckingPass(unsigned Penalty) {
545 return new BoundsChecking(Penalty);
546}