blob: d10d97ca050e088cd693a6ad0998e158b4659d26 [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 Lopesacee9e72012-06-01 17:43:31 +000058 CacheData() {}
59 CacheData(APInt Off, Value *OffVal, APInt Sz, Value *SzVal, bool Ret) :
60 Offset(Off), OffsetValue(OffVal), Size(Sz), SizeValue(SzVal),
61 ReturnVal(Ret) {}
Nuno Lopes5c525b52012-05-22 17:19:09 +000062 };
Nuno Lopes0463cce2012-05-31 22:45:40 +000063 typedef DenseMap<Value*, CacheData> CacheMapTy;
Nuno Lopesacee9e72012-06-01 17:43:31 +000064 typedef SmallPtrSet<Value*, 8> PtrSetTy;
Nuno Lopes5c525b52012-05-22 17:19:09 +000065
66 struct BoundsChecking : public FunctionPass {
Nuno Lopes5c525b52012-05-22 17:19:09 +000067 static char ID;
68
69 BoundsChecking(unsigned _Penalty = 5) : FunctionPass(ID), Penalty(_Penalty){
70 initializeBoundsCheckingPass(*PassRegistry::getPassRegistry());
71 }
72
Nuno Lopes5c525b52012-05-22 17:19:09 +000073 virtual bool runOnFunction(Function &F);
74
75 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
76 AU.addRequired<TargetData>();
Nuno Lopes988a0892012-05-29 22:32:51 +000077 AU.addRequired<LoopInfo>();
78 AU.addRequired<ScalarEvolution>();
Nuno Lopes5c525b52012-05-22 17:19:09 +000079 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +000080
81 private:
82 const TargetData *TD;
Nuno Lopes988a0892012-05-29 22:32:51 +000083 LoopInfo *LI;
84 ScalarEvolution *SE;
Nuno Lopes2f0a7482012-05-22 22:02:19 +000085 BuilderTy *Builder;
86 Function *Fn;
87 BasicBlock *TrapBB;
88 unsigned Penalty;
Nuno Lopes0463cce2012-05-31 22:45:40 +000089 CacheMapTy CacheMap;
Nuno Lopesacee9e72012-06-01 17:43:31 +000090 PtrSetTy SeenPtrs;
Nuno Lopes2f0a7482012-05-22 22:02:19 +000091
92 BasicBlock *getTrapBB();
Nuno Lopes2b526302012-05-23 16:24:52 +000093 void emitBranchToTrap(Value *Cmp = 0);
Nuno Lopes0463cce2012-05-31 22:45:40 +000094 bool computeAllocSize(Value *Ptr, APInt &Offset, Value* &OffsetValue,
95 APInt &Size, Value* &SizeValue);
Nuno Lopes2f0a7482012-05-22 22:02:19 +000096 bool instrument(Value *Ptr, Value *Val);
Nuno Lopes5c525b52012-05-22 17:19:09 +000097 };
98}
99
100char BoundsChecking::ID = 0;
Nuno Lopes988a0892012-05-29 22:32:51 +0000101INITIALIZE_PASS_BEGIN(BoundsChecking, "bounds-checking",
102 "Run-time bounds checking", false, false)
103INITIALIZE_PASS_DEPENDENCY(ScalarEvolution)
104INITIALIZE_PASS_END(BoundsChecking, "bounds-checking",
105 "Run-time bounds checking", false, false)
Nuno Lopes5c525b52012-05-22 17:19:09 +0000106
107
108/// getTrapBB - create a basic block that traps. All overflowing conditions
109/// branch to this block. There's only one trap block per function.
110BasicBlock *BoundsChecking::getTrapBB() {
Nuno Lopes1cbf2be2012-05-31 22:58:48 +0000111 if (TrapBB && !ManyTrapBB)
Nuno Lopes5c525b52012-05-22 17:19:09 +0000112 return TrapBB;
113
114 BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint();
115 TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
116 Builder->SetInsertPoint(TrapBB);
117
118 llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap);
119 CallInst *TrapCall = Builder->CreateCall(F);
120 TrapCall->setDoesNotReturn();
121 TrapCall->setDoesNotThrow();
122 Builder->CreateUnreachable();
123
124 Builder->SetInsertPoint(PrevInsertPoint);
125 return TrapBB;
126}
127
128
Nuno Lopes2b526302012-05-23 16:24:52 +0000129/// emitBranchToTrap - emit a branch instruction to a trap block.
130/// If Cmp is non-null, perform a jump only if its value evaluates to true.
131void BoundsChecking::emitBranchToTrap(Value *Cmp) {
132 Instruction *Inst = Builder->GetInsertPoint();
133 BasicBlock *OldBB = Inst->getParent();
134 BasicBlock *Cont = OldBB->splitBasicBlock(Inst);
135 OldBB->getTerminator()->eraseFromParent();
136
Nuno Lopes2b526302012-05-23 16:24:52 +0000137 if (Cmp)
138 BranchInst::Create(getTrapBB(), Cont, Cmp, OldBB);
139 else
140 BranchInst::Create(getTrapBB(), OldBB);
141}
142
143
Nuno Lopes0463cce2012-05-31 22:45:40 +0000144#define GET_VALUE(Val, Int) \
145 if (!Val) \
146 Val = ConstantInt::get(IntTy, Int)
147
148#define RETURN(Val) \
149 do { ReturnVal = Val; goto cache_and_return; } while (0)
150
151/// computeAllocSize - compute the object size and the offset within the object
152/// pointed by Ptr. OffsetValue/SizeValue will be null if they are constant, and
153/// therefore the result is given in Offset/Size variables instead.
154/// Returns true if the offset and size could be computed within the given
155/// maximum run-time penalty.
156bool BoundsChecking::computeAllocSize(Value *Ptr, APInt &Offset,
157 Value* &OffsetValue, APInt &Size,
158 Value* &SizeValue) {
159 Ptr = Ptr->stripPointerCasts();
160
161 // lookup to see if we've seen the Ptr before
162 CacheMapTy::iterator CacheIt = CacheMap.find(Ptr);
163 if (CacheIt != CacheMap.end()) {
164 CacheData &Cache = CacheIt->second;
165 Offset = Cache.Offset;
166 OffsetValue = Cache.OffsetValue;
167 Size = Cache.Size;
168 SizeValue = Cache.SizeValue;
169 return Cache.ReturnVal;
170 }
171
Nuno Lopesacee9e72012-06-01 17:43:31 +0000172 // record the pointers that were handled in this run, so that they can be
173 // cleaned later if something fails
174 SeenPtrs.insert(Ptr);
175
Nuno Lopes0463cce2012-05-31 22:45:40 +0000176 IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
177 unsigned IntTyBits = IntTy->getBitWidth();
178 bool ReturnVal;
179
180 // always generate code immediately before the instruction being processed, so
181 // that the generated code dominates the same BBs
182 Instruction *PrevInsertPoint = Builder->GetInsertPoint();
183 if (Instruction *I = dyn_cast<Instruction>(Ptr))
184 Builder->SetInsertPoint(I);
185
186 // initalize with "don't know" state: offset=0 and size=uintmax
187 Offset = 0;
188 Size = APInt::getMaxValue(TD->getTypeSizeInBits(IntTy));
189 OffsetValue = SizeValue = 0;
190
191 if (GEPOperator *GEP = dyn_cast<GEPOperator>(Ptr)) {
192 APInt PtrOffset(IntTyBits, 0);
193 Value *PtrOffsetValue = 0;
194 if (!computeAllocSize(GEP->getPointerOperand(), PtrOffset, PtrOffsetValue,
195 Size, SizeValue))
196 RETURN(false);
197
198 if (GEP->hasAllConstantIndices()) {
199 SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
200 Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
201 // if PtrOffset is constant, return immediately
202 if (!PtrOffsetValue) {
203 Offset += PtrOffset;
204 RETURN(true);
205 }
206 OffsetValue = ConstantInt::get(IntTy, Offset);
Nuno Lopesacee9e72012-06-01 17:43:31 +0000207 } else if (Penalty > 1) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000208 OffsetValue = EmitGEPOffset(Builder, *TD, GEP);
Nuno Lopesacee9e72012-06-01 17:43:31 +0000209 GET_VALUE(PtrOffsetValue, PtrOffset);
210 } else
211 RETURN(false);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000212
Nuno Lopes0463cce2012-05-31 22:45:40 +0000213 OffsetValue = Builder->CreateAdd(PtrOffsetValue, OffsetValue);
214 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000215
216 // global variable with definitive size
Nuno Lopes0463cce2012-05-31 22:45:40 +0000217 } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Ptr)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000218 if (GV->hasDefinitiveInitializer()) {
219 Constant *C = GV->getInitializer();
220 Size = TD->getTypeAllocSize(C->getType());
Nuno Lopes0463cce2012-05-31 22:45:40 +0000221 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000222 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000223 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000224
Nuno Lopes6a06e682012-05-25 16:54:04 +0000225 // stack allocation
Nuno Lopes0463cce2012-05-31 22:45:40 +0000226 } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Ptr)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000227 if (!AI->getAllocatedType()->isSized())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000228 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000229
230 Size = TD->getTypeAllocSize(AI->getAllocatedType());
231 if (!AI->isArrayAllocation())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000232 RETURN(true); // we are done
Nuno Lopes5c525b52012-05-22 17:19:09 +0000233
234 Value *ArraySize = AI->getArraySize();
235 if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000236 Size *= C->getValue();
237 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000238 }
239
240 if (Penalty < 2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000241 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000242
Nuno Lopes0463cce2012-05-31 22:45:40 +0000243 // VLA: compute size dynamically
Nuno Lopes5c525b52012-05-22 17:19:09 +0000244 SizeValue = ConstantInt::get(ArraySize->getType(), Size);
245 SizeValue = Builder->CreateMul(SizeValue, ArraySize);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000246 RETURN(true);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000247
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000248 // function arguments
Nuno Lopes0463cce2012-05-31 22:45:40 +0000249 } else if (Argument *A = dyn_cast<Argument>(Ptr)) {
250 // right now we only support byval arguments, so that no interprocedural
251 // analysis is necessary
Nuno Lopes988a0892012-05-29 22:32:51 +0000252 if (!A->hasByValAttr()) {
253 ++ChecksUnableInterproc;
Nuno Lopes0463cce2012-05-31 22:45:40 +0000254 RETURN(false);
Nuno Lopes988a0892012-05-29 22:32:51 +0000255 }
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000256
257 PointerType *PT = cast<PointerType>(A->getType());
258 Size = TD->getTypeAllocSize(PT->getElementType());
Nuno Lopes0463cce2012-05-31 22:45:40 +0000259 RETURN(true);
Nuno Lopesd72d67d2012-05-25 21:15:17 +0000260
Nuno Lopes6a06e682012-05-25 16:54:04 +0000261 // ptr = select(ptr1, ptr2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000262 } else if (SelectInst *SI = dyn_cast<SelectInst>(Ptr)) {
263 APInt OffsetTrue(IntTyBits, 0), OffsetFalse(IntTyBits, 0);
264 APInt SizeTrue(IntTyBits, 0), SizeFalse(IntTyBits, 0);
265 Value *OffsetValueTrue = 0, *OffsetValueFalse = 0;
266 Value *SizeValueTrue = 0, *SizeValueFalse = 0;
Nuno Lopes6a06e682012-05-25 16:54:04 +0000267
Nuno Lopes0463cce2012-05-31 22:45:40 +0000268 bool TrueAlloc = computeAllocSize(SI->getTrueValue(), OffsetTrue,
269 OffsetValueTrue, SizeTrue, SizeValueTrue);
270 bool FalseAlloc = computeAllocSize(SI->getFalseValue(), OffsetFalse,
271 OffsetValueFalse, SizeFalse,
272 SizeValueFalse);
Nuno Lopesacee9e72012-06-01 17:43:31 +0000273 if (!TrueAlloc || !FalseAlloc)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000274 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000275
Nuno Lopes0463cce2012-05-31 22:45:40 +0000276 // fold constant sizes & offsets if they are equal
277 if (!OffsetValueTrue && !OffsetValueFalse && OffsetTrue == OffsetFalse)
278 Offset = OffsetTrue;
279 else if (Penalty > 1) {
280 GET_VALUE(OffsetValueTrue, OffsetTrue);
281 GET_VALUE(OffsetValueFalse, OffsetFalse);
282 OffsetValue = Builder->CreateSelect(SI->getCondition(), OffsetValueTrue,
283 OffsetValueFalse);
284 } else
285 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000286
Nuno Lopes0463cce2012-05-31 22:45:40 +0000287 if (!SizeValueTrue && !SizeValueFalse && SizeTrue == SizeFalse)
288 Size = SizeTrue;
289 else if (Penalty > 1) {
290 GET_VALUE(SizeValueTrue, SizeTrue);
291 GET_VALUE(SizeValueFalse, SizeFalse);
292 SizeValue = Builder->CreateSelect(SI->getCondition(), SizeValueTrue,
293 SizeValueFalse);
294 } else
295 RETURN(false);
296 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000297
298 // call allocation function
Nuno Lopes0463cce2012-05-31 22:45:40 +0000299 } else if (CallInst *CI = dyn_cast<CallInst>(Ptr)) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000300 SmallVector<unsigned, 4> Args;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000301
Nuno Lopes6a06e682012-05-25 16:54:04 +0000302 if (MDNode *MD = CI->getMetadata("alloc_size")) {
303 for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i)
304 Args.push_back(cast<ConstantInt>(MD->getOperand(i))->getZExtValue());
305
306 } else if (Function *Callee = CI->getCalledFunction()) {
307 FunctionType *FTy = Callee->getFunctionType();
308
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000309 // alloc(size)
Nuno Lopes6a06e682012-05-25 16:54:04 +0000310 if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy()) {
311 if ((Callee->getName() == "malloc" ||
312 Callee->getName() == "valloc" ||
313 Callee->getName() == "_Znwj" || // operator new(unsigned int)
314 Callee->getName() == "_Znwm" || // operator new(unsigned long)
315 Callee->getName() == "_Znaj" || // operator new[](unsigned int)
316 Callee->getName() == "_Znam")) {
317 Args.push_back(0);
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000318 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000319 } else if (FTy->getNumParams() == 2) {
320 // alloc(_, x)
321 if (FTy->getParamType(1)->isIntegerTy() &&
322 ((Callee->getName() == "realloc" ||
323 Callee->getName() == "reallocf"))) {
324 Args.push_back(1);
325
326 // alloc(x, y)
327 } else if (FTy->getParamType(0)->isIntegerTy() &&
328 FTy->getParamType(1)->isIntegerTy() &&
329 Callee->getName() == "calloc") {
330 Args.push_back(0);
331 Args.push_back(1);
332 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000333 } else if (FTy->getNumParams() == 3) {
334 // alloc(_, _, x)
335 if (FTy->getParamType(2)->isIntegerTy() &&
336 Callee->getName() == "posix_memalign") {
337 Args.push_back(2);
338 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000339 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000340 }
341
342 if (Args.empty())
Nuno Lopes0463cce2012-05-31 22:45:40 +0000343 RETURN(false);
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000344
Nuno Lopes6a06e682012-05-25 16:54:04 +0000345 // check if all arguments are constant. if so, the object size is also const
346 bool AllConst = true;
347 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
348 I != E; ++I) {
349 if (!isa<ConstantInt>(CI->getArgOperand(*I))) {
350 AllConst = false;
351 break;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000352 }
353 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000354
355 if (AllConst) {
356 Size = 1;
357 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
358 I != E; ++I) {
359 ConstantInt *Arg = cast<ConstantInt>(CI->getArgOperand(*I));
Nuno Lopes0463cce2012-05-31 22:45:40 +0000360 Size *= Arg->getValue().zextOrSelf(IntTyBits);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000361 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000362 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000363 }
364
365 if (Penalty < 2)
Nuno Lopes0463cce2012-05-31 22:45:40 +0000366 RETURN(false);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000367
368 // not all arguments are constant, so create a sequence of multiplications
Nuno Lopes6a06e682012-05-25 16:54:04 +0000369 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
370 I != E; ++I) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000371 Value *Arg = Builder->CreateZExt(CI->getArgOperand(*I), IntTy);
372 if (!SizeValue) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000373 SizeValue = Arg;
Nuno Lopes6a06e682012-05-25 16:54:04 +0000374 continue;
375 }
376 SizeValue = Builder->CreateMul(SizeValue, Arg);
377 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000378 RETURN(true);
Nuno Lopes6a06e682012-05-25 16:54:04 +0000379
Nuno Lopeseb90adf2012-06-08 16:31:42 +0000380 // TODO: handle more standard functions (+ wchar cousins):
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000381 // - strdup / strndup
382 // - strcpy / strncpy
Nuno Lopeseb90adf2012-06-08 16:31:42 +0000383 // - strcat / strncat
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000384 // - memcpy / memmove
385 // - strcat / strncat
Nuno Lopeseb90adf2012-06-08 16:31:42 +0000386 // - memset
Nuno Lopes988a0892012-05-29 22:32:51 +0000387
Nuno Lopes0463cce2012-05-31 22:45:40 +0000388 } else if (PHINode *PHI = dyn_cast<PHINode>(Ptr)) {
389 // create 2 PHIs: one for offset and another for size
390 PHINode *OffsetPHI = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
391 PHINode *SizePHI = Builder->CreatePHI(IntTy, PHI->getNumIncomingValues());
392
393 // insert right away in the cache to handle recursive PHIs
Nuno Lopeseb90adf2012-06-08 16:31:42 +0000394 CacheMap[Ptr] = CacheData(APInt(), OffsetPHI, APInt(), SizePHI, true);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000395
396 // compute offset/size for each PHI incoming pointer
Nuno Lopes0463cce2012-05-31 22:45:40 +0000397 for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) {
398 Builder->SetInsertPoint(PHI->getIncomingBlock(i)->getFirstInsertionPt());
399
400 APInt PhiOffset(IntTyBits, 0), PhiSize(IntTyBits, 0);
401 Value *PhiOffsetValue = 0, *PhiSizeValue = 0;
Nuno Lopesacee9e72012-06-01 17:43:31 +0000402
403 if (!computeAllocSize(PHI->getIncomingValue(i), PhiOffset, PhiOffsetValue,
404 PhiSize, PhiSizeValue)) {
405 OffsetPHI->replaceAllUsesWith(UndefValue::get(IntTy));
406 OffsetPHI->eraseFromParent();
407 SizePHI->replaceAllUsesWith(UndefValue::get(IntTy));
408 SizePHI->eraseFromParent();
409 RETURN(false);
410 }
Nuno Lopes0463cce2012-05-31 22:45:40 +0000411
412 GET_VALUE(PhiOffsetValue, PhiOffset);
413 GET_VALUE(PhiSizeValue, PhiSize);
414
415 OffsetPHI->addIncoming(PhiOffsetValue, PHI->getIncomingBlock(i));
416 SizePHI->addIncoming(PhiSizeValue, PHI->getIncomingBlock(i));
417 }
418
Nuno Lopes0463cce2012-05-31 22:45:40 +0000419 OffsetValue = OffsetPHI;
420 SizeValue = SizePHI;
421 RETURN(true);
422
Nuno Lopeseb90adf2012-06-08 16:31:42 +0000423 } else if (isa<UndefValue>(Ptr) || isa<ConstantPointerNull>(Ptr)) {
Nuno Lopes0463cce2012-05-31 22:45:40 +0000424 Size = 0;
425 RETURN(true);
426
427 } else if (isa<LoadInst>(Ptr)) {
Nuno Lopes988a0892012-05-29 22:32:51 +0000428 ++ChecksUnableLoad;
Nuno Lopes0463cce2012-05-31 22:45:40 +0000429 RETURN(false);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000430 }
431
Nuno Lopeseb90adf2012-06-08 16:31:42 +0000432 DEBUG(dbgs() << "computeAllocSize unhandled value:\n" << *Ptr << "\n");
Nuno Lopes0463cce2012-05-31 22:45:40 +0000433 RETURN(false);
434
435cache_and_return:
436 // cache the result and return
Nuno Lopeseb90adf2012-06-08 16:31:42 +0000437 CacheMap[Ptr] = CacheData(Offset, OffsetValue, Size, SizeValue, ReturnVal);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000438
Nuno Lopesacee9e72012-06-01 17:43:31 +0000439 // non-computable results can be safely cached
440 if (!ReturnVal)
441 SeenPtrs.erase(Ptr);
442
Nuno Lopes0463cce2012-05-31 22:45:40 +0000443 Builder->SetInsertPoint(PrevInsertPoint);
444 return ReturnVal;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000445}
446
447
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000448/// instrument - adds run-time bounds checks to memory accessing instructions.
449/// Ptr is the pointer that will be read/written, and InstVal is either the
450/// result from the load or the value being stored. It is used to determine the
451/// size of memory block that is touched.
452/// Returns true if any change was made to the IR, false otherwise.
Nuno Lopes5c525b52012-05-22 17:19:09 +0000453bool BoundsChecking::instrument(Value *Ptr, Value *InstVal) {
454 uint64_t NeededSize = TD->getTypeStoreSize(InstVal->getType());
455 DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize)
456 << " bytes\n");
457
Nuno Lopes0463cce2012-05-31 22:45:40 +0000458 IntegerType *IntTy = TD->getIntPtrType(Fn->getContext());
459 unsigned IntTyBits = IntTy->getBitWidth();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000460
Nuno Lopes0463cce2012-05-31 22:45:40 +0000461 APInt Offset(IntTyBits, 0), Size(IntTyBits, 0);
462 Value *OffsetValue = 0, *SizeValue = 0;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000463
Nuno Lopes0463cce2012-05-31 22:45:40 +0000464 if (!computeAllocSize(Ptr, Offset, OffsetValue, Size, SizeValue)) {
Nuno Lopes988a0892012-05-29 22:32:51 +0000465 DEBUG(dbgs() << "computeAllocSize failed:\n" << *Ptr << "\n");
Nuno Lopesacee9e72012-06-01 17:43:31 +0000466
467 // erase everything that was computed in this iteration from the cache, so
468 // that no dangling references are left behind. We could be a bit smarter if
469 // we kept a dependency graph. It's probably not worth the complexity,
470 // though.
471 for (PtrSetTy::iterator I=SeenPtrs.begin(), E=SeenPtrs.end(); I != E; ++I)
472 CacheMap.erase(*I);
473 SeenPtrs.clear();
474
Nuno Lopes5c525b52012-05-22 17:19:09 +0000475 ++ChecksUnable;
476 return false;
477 }
Nuno Lopes5c525b52012-05-22 17:19:09 +0000478
Nuno Lopes0463cce2012-05-31 22:45:40 +0000479 // three checks are required to ensure safety:
480 // . Offset >= 0 (since the offset is given from the base ptr)
481 // . Size >= Offset (unsigned)
482 // . Size - Offset >= NeededSize (unsigned)
483 if (!OffsetValue && !SizeValue) {
484 if (Offset.slt(0) || Size.ult(Offset) || (Size - Offset).ult(NeededSize)) {
Nuno Lopes5c525b52012-05-22 17:19:09 +0000485 // Out of bounds
Nuno Lopes2b526302012-05-23 16:24:52 +0000486 emitBranchToTrap();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000487 ++ChecksAdded;
488 return true;
489 }
490 // in bounds
491 ++ChecksSkipped;
492 return false;
493 }
494
Nuno Lopes0463cce2012-05-31 22:45:40 +0000495 // emit check for offset < 0
496 Value *CmpOffset = 0;
497 if (OffsetValue)
498 CmpOffset = Builder->CreateICmpSLT(OffsetValue, ConstantInt::get(IntTy, 0));
499 else if (Offset.slt(0)) {
500 // offset proved to be negative
501 emitBranchToTrap();
502 ++ChecksAdded;
503 return true;
504 }
Nuno Lopes5c525b52012-05-22 17:19:09 +0000505
Nuno Lopes0463cce2012-05-31 22:45:40 +0000506 // we couldn't determine statically if the memory access is safe; emit a
507 // run-time check
508 GET_VALUE(OffsetValue, Offset);
509 GET_VALUE(SizeValue, Size);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000510
Nuno Lopes0463cce2012-05-31 22:45:40 +0000511 Value *NeededSizeVal = ConstantInt::get(IntTy, NeededSize);
512 // FIXME: add NSW/NUW here? -- we dont care if the subtraction overflows
Nuno Lopes5c525b52012-05-22 17:19:09 +0000513 Value *ObjSize = Builder->CreateSub(SizeValue, OffsetValue);
514 Value *Cmp1 = Builder->CreateICmpULT(SizeValue, OffsetValue);
515 Value *Cmp2 = Builder->CreateICmpULT(ObjSize, NeededSizeVal);
516 Value *Or = Builder->CreateOr(Cmp1, Cmp2);
Nuno Lopes0463cce2012-05-31 22:45:40 +0000517 if (CmpOffset)
518 Or = Builder->CreateOr(CmpOffset, Or);
Nuno Lopes2b526302012-05-23 16:24:52 +0000519 emitBranchToTrap(Or);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000520
Nuno Lopes5c525b52012-05-22 17:19:09 +0000521 ++ChecksAdded;
522 return true;
523}
524
525bool BoundsChecking::runOnFunction(Function &F) {
526 TD = &getAnalysis<TargetData>();
Nuno Lopes988a0892012-05-29 22:32:51 +0000527 LI = &getAnalysis<LoopInfo>();
528 SE = &getAnalysis<ScalarEvolution>();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000529
530 TrapBB = 0;
531 Fn = &F;
532 BuilderTy TheBuilder(F.getContext(), TargetFolder(TD));
533 Builder = &TheBuilder;
534
535 // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory
536 // touching instructions
537 std::vector<Instruction*> WorkList;
538 for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
539 Instruction *I = &*i;
540 if (isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) ||
541 isa<AtomicRMWInst>(I))
542 WorkList.push_back(I);
543 }
544
545 bool MadeChange = false;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000546 for (std::vector<Instruction*>::iterator i = WorkList.begin(),
547 e = WorkList.end(); i != e; ++i) {
548 Instruction *I = *i;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000549
550 Builder->SetInsertPoint(I);
551 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
552 MadeChange |= instrument(LI->getPointerOperand(), LI);
553 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
554 MadeChange |= instrument(SI->getPointerOperand(), SI->getValueOperand());
555 } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(I)) {
556 MadeChange |= instrument(AI->getPointerOperand(),AI->getCompareOperand());
557 } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(I)) {
558 MadeChange |= instrument(AI->getPointerOperand(), AI->getValOperand());
559 } else {
560 llvm_unreachable("unknown Instruction type");
561 }
562 }
563 return MadeChange;
564}
565
566FunctionPass *llvm::createBoundsCheckingPass(unsigned Penalty) {
567 return new BoundsChecking(Penalty);
568}