blob: 4c3dea2317a0263459035ae0f0a5147c0dac1d44 [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"
17#include "llvm/ADT/Statistic.h"
18#include "llvm/Analysis/MemoryBuiltins.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/InstIterator.h"
21#include "llvm/Support/IRBuilder.h"
Nuno Lopes2f0a7482012-05-22 22:02:19 +000022#include "llvm/Support/raw_ostream.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000023#include "llvm/Support/TargetFolder.h"
24#include "llvm/Target/TargetData.h"
25#include "llvm/Transforms/Utils/Local.h"
26#include "llvm/GlobalVariable.h"
27#include "llvm/Instructions.h"
28#include "llvm/Intrinsics.h"
Nuno Lopes6a06e682012-05-25 16:54:04 +000029#include "llvm/Metadata.h"
Nuno Lopes5c525b52012-05-22 17:19:09 +000030#include "llvm/Operator.h"
31#include "llvm/Pass.h"
32using namespace llvm;
33
34STATISTIC(ChecksAdded, "Bounds checks added");
35STATISTIC(ChecksSkipped, "Bounds checks skipped");
36STATISTIC(ChecksUnable, "Bounds checks unable to add");
37
38typedef IRBuilder<true, TargetFolder> BuilderTy;
39
40namespace {
41 enum ConstTriState {
42 NotConst, Const, Dunno
43 };
44
45 struct BoundsChecking : public FunctionPass {
Nuno Lopes5c525b52012-05-22 17:19:09 +000046 static char ID;
47
48 BoundsChecking(unsigned _Penalty = 5) : FunctionPass(ID), Penalty(_Penalty){
49 initializeBoundsCheckingPass(*PassRegistry::getPassRegistry());
50 }
51
Nuno Lopes5c525b52012-05-22 17:19:09 +000052 virtual bool runOnFunction(Function &F);
53
54 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
55 AU.addRequired<TargetData>();
56 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +000057
58 private:
59 const TargetData *TD;
60 BuilderTy *Builder;
61 Function *Fn;
62 BasicBlock *TrapBB;
63 unsigned Penalty;
64
65 BasicBlock *getTrapBB();
Nuno Lopes2b526302012-05-23 16:24:52 +000066 void emitBranchToTrap(Value *Cmp = 0);
Nuno Lopes2f0a7482012-05-22 22:02:19 +000067 ConstTriState computeAllocSize(Value *Alloc, uint64_t &Size,
68 Value* &SizeValue);
69 bool instrument(Value *Ptr, Value *Val);
Nuno Lopes5c525b52012-05-22 17:19:09 +000070 };
71}
72
73char BoundsChecking::ID = 0;
74INITIALIZE_PASS(BoundsChecking, "bounds-checking", "Run-time bounds checking",
75 false, false)
76
77
78/// getTrapBB - create a basic block that traps. All overflowing conditions
79/// branch to this block. There's only one trap block per function.
80BasicBlock *BoundsChecking::getTrapBB() {
81 if (TrapBB)
82 return TrapBB;
83
84 BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint();
85 TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
86 Builder->SetInsertPoint(TrapBB);
87
88 llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap);
89 CallInst *TrapCall = Builder->CreateCall(F);
90 TrapCall->setDoesNotReturn();
91 TrapCall->setDoesNotThrow();
92 Builder->CreateUnreachable();
93
94 Builder->SetInsertPoint(PrevInsertPoint);
95 return TrapBB;
96}
97
98
Nuno Lopes2b526302012-05-23 16:24:52 +000099/// emitBranchToTrap - emit a branch instruction to a trap block.
100/// If Cmp is non-null, perform a jump only if its value evaluates to true.
101void BoundsChecking::emitBranchToTrap(Value *Cmp) {
102 Instruction *Inst = Builder->GetInsertPoint();
103 BasicBlock *OldBB = Inst->getParent();
104 BasicBlock *Cont = OldBB->splitBasicBlock(Inst);
105 OldBB->getTerminator()->eraseFromParent();
106
107 // FIXME: add unlikely branch taken metadata?
108 if (Cmp)
109 BranchInst::Create(getTrapBB(), Cont, Cmp, OldBB);
110 else
111 BranchInst::Create(getTrapBB(), OldBB);
112}
113
114
Nuno Lopes5c525b52012-05-22 17:19:09 +0000115/// computeAllocSize - compute the object size allocated by an allocation
116/// site. Returns NotConst if the size is not constant (in SizeValue), Const if
117/// the size is constant (in Size), and Dunno if the size could not be
118/// determined within the given maximum Penalty that the computation would
119/// incurr at run-time.
120ConstTriState BoundsChecking::computeAllocSize(Value *Alloc, uint64_t &Size,
121 Value* &SizeValue) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000122 IntegerType *RetTy = TD->getIntPtrType(Fn->getContext());
123
124 // global variable with definitive size
Nuno Lopes5c525b52012-05-22 17:19:09 +0000125 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Alloc)) {
126 if (GV->hasDefinitiveInitializer()) {
127 Constant *C = GV->getInitializer();
128 Size = TD->getTypeAllocSize(C->getType());
129 return Const;
130 }
131 return Dunno;
132
Nuno Lopes6a06e682012-05-25 16:54:04 +0000133 // stack allocation
Nuno Lopes5c525b52012-05-22 17:19:09 +0000134 } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Alloc)) {
135 if (!AI->getAllocatedType()->isSized())
136 return Dunno;
137
138 Size = TD->getTypeAllocSize(AI->getAllocatedType());
139 if (!AI->isArrayAllocation())
140 return Const; // we are done
141
142 Value *ArraySize = AI->getArraySize();
143 if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
144 Size *= C->getZExtValue();
145 return Const;
146 }
147
148 if (Penalty < 2)
149 return Dunno;
150
151 SizeValue = ConstantInt::get(ArraySize->getType(), Size);
152 SizeValue = Builder->CreateMul(SizeValue, ArraySize);
153 return NotConst;
154
Nuno Lopes6a06e682012-05-25 16:54:04 +0000155 // ptr = select(ptr1, ptr2)
156 } else if (SelectInst *SI = dyn_cast<SelectInst>(Alloc)) {
157 uint64_t SizeFalse;
158 Value *SizeValueFalse;
159 ConstTriState TrueConst = computeAllocSize(SI->getTrueValue(), Size,
160 SizeValue);
161 ConstTriState FalseConst = computeAllocSize(SI->getFalseValue(), SizeFalse,
162 SizeValueFalse);
163
164 if (TrueConst == Const && FalseConst == Const && Size == SizeFalse)
165 return Const;
166
167 if (Penalty < 2 || (TrueConst == Dunno && FalseConst == Dunno))
168 return Dunno;
169
170 // if one of the branches is Dunno, assume it is ok and check just the other
171 APInt MaxSize = APInt::getMaxValue(TD->getTypeSizeInBits(RetTy));
172
173 if (TrueConst == Const)
174 SizeValue = ConstantInt::get(RetTy, Size);
175 else if (TrueConst == Dunno)
176 SizeValue = ConstantInt::get(RetTy, MaxSize);
177
178 if (FalseConst == Const)
179 SizeValueFalse = ConstantInt::get(RetTy, SizeFalse);
180 else if (FalseConst == Dunno)
181 SizeValueFalse = ConstantInt::get(RetTy, MaxSize);
182
183 SizeValue = Builder->CreateSelect(SI->getCondition(), SizeValue,
184 SizeValueFalse);
185 return NotConst;
186
187 // call allocation function
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000188 } else if (CallInst *CI = dyn_cast<CallInst>(Alloc)) {
Nuno Lopes6a06e682012-05-25 16:54:04 +0000189 SmallVector<unsigned, 4> Args;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000190
Nuno Lopes6a06e682012-05-25 16:54:04 +0000191 if (MDNode *MD = CI->getMetadata("alloc_size")) {
192 for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i)
193 Args.push_back(cast<ConstantInt>(MD->getOperand(i))->getZExtValue());
194
195 } else if (Function *Callee = CI->getCalledFunction()) {
196 FunctionType *FTy = Callee->getFunctionType();
197
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000198 // alloc(size)
Nuno Lopes6a06e682012-05-25 16:54:04 +0000199 if (FTy->getNumParams() == 1 && FTy->getParamType(0)->isIntegerTy()) {
200 if ((Callee->getName() == "malloc" ||
201 Callee->getName() == "valloc" ||
202 Callee->getName() == "_Znwj" || // operator new(unsigned int)
203 Callee->getName() == "_Znwm" || // operator new(unsigned long)
204 Callee->getName() == "_Znaj" || // operator new[](unsigned int)
205 Callee->getName() == "_Znam")) {
206 Args.push_back(0);
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000207 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000208 } else if (FTy->getNumParams() == 2) {
209 // alloc(_, x)
210 if (FTy->getParamType(1)->isIntegerTy() &&
211 ((Callee->getName() == "realloc" ||
212 Callee->getName() == "reallocf"))) {
213 Args.push_back(1);
214
215 // alloc(x, y)
216 } else if (FTy->getParamType(0)->isIntegerTy() &&
217 FTy->getParamType(1)->isIntegerTy() &&
218 Callee->getName() == "calloc") {
219 Args.push_back(0);
220 Args.push_back(1);
221 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000222 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000223 }
224
225 if (Args.empty())
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000226 return Dunno;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000227
Nuno Lopes6a06e682012-05-25 16:54:04 +0000228 // check if all arguments are constant. if so, the object size is also const
229 bool AllConst = true;
230 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
231 I != E; ++I) {
232 if (!isa<ConstantInt>(CI->getArgOperand(*I))) {
233 AllConst = false;
234 break;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000235 }
236 }
Nuno Lopes6a06e682012-05-25 16:54:04 +0000237
238 if (AllConst) {
239 Size = 1;
240 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
241 I != E; ++I) {
242 ConstantInt *Arg = cast<ConstantInt>(CI->getArgOperand(*I));
243 Size *= (size_t)Arg->getZExtValue();
244 }
245 return Const;
246 }
247
248 if (Penalty < 2)
249 return Dunno;
250
251 // not all arguments are constant, so create a sequence of multiplications
252 bool First = true;
253 for (SmallVectorImpl<unsigned>::iterator I = Args.begin(), E = Args.end();
254 I != E; ++I) {
255 Value *Arg = CI->getArgOperand(*I);
256 if (First) {
257 SizeValue = Arg;
258 First = false;
259 continue;
260 }
261 SizeValue = Builder->CreateMul(SizeValue, Arg);
262 }
263
264 return NotConst;
265
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000266 // TODO: handle more standard functions:
267 // - strdup / strndup
268 // - strcpy / strncpy
269 // - memcpy / memmove
270 // - strcat / strncat
Nuno Lopes5c525b52012-05-22 17:19:09 +0000271 }
272
Nuno Lopes6a06e682012-05-25 16:54:04 +0000273 DEBUG(dbgs() << "computeAllocSize failed:\n" << *Alloc << "\n");
Nuno Lopes5c525b52012-05-22 17:19:09 +0000274 return Dunno;
275}
276
277
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000278/// instrument - adds run-time bounds checks to memory accessing instructions.
279/// Ptr is the pointer that will be read/written, and InstVal is either the
280/// result from the load or the value being stored. It is used to determine the
281/// size of memory block that is touched.
282/// Returns true if any change was made to the IR, false otherwise.
Nuno Lopes5c525b52012-05-22 17:19:09 +0000283bool BoundsChecking::instrument(Value *Ptr, Value *InstVal) {
284 uint64_t NeededSize = TD->getTypeStoreSize(InstVal->getType());
285 DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize)
286 << " bytes\n");
287
288 Type *SizeTy = Type::getInt64Ty(Fn->getContext());
289
290 // Get to the real allocated thing and offset as fast as possible.
291 Ptr = Ptr->stripPointerCasts();
292 GEPOperator *GEP;
293
294 if ((GEP = dyn_cast<GEPOperator>(Ptr))) {
295 // check if we will be able to get the offset
296 if (!GEP->hasAllConstantIndices() && Penalty < 2) {
297 ++ChecksUnable;
298 return false;
299 }
300 Ptr = GEP->getPointerOperand()->stripPointerCasts();
301 }
302
303 uint64_t Size = 0;
304 Value *SizeValue = 0;
305 ConstTriState ConstAlloc = computeAllocSize(Ptr, Size, SizeValue);
306 if (ConstAlloc == Dunno) {
307 ++ChecksUnable;
308 return false;
309 }
310 assert(ConstAlloc == Const || SizeValue);
311
312 uint64_t Offset = 0;
313 Value *OffsetValue = 0;
314
315 if (GEP) {
316 if (GEP->hasAllConstantIndices()) {
317 SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
318 assert(GEP->getPointerOperandType()->isPointerTy());
319 Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
320 } else {
321 OffsetValue = EmitGEPOffset(Builder, *TD, GEP);
322 }
323 }
324
325 if (!OffsetValue && ConstAlloc == Const) {
326 if (Size < Offset || (Size - Offset) < NeededSize) {
327 // Out of bounds
Nuno Lopes2b526302012-05-23 16:24:52 +0000328 emitBranchToTrap();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000329 ++ChecksAdded;
330 return true;
331 }
332 // in bounds
333 ++ChecksSkipped;
334 return false;
335 }
336
337 if (OffsetValue)
338 OffsetValue = Builder->CreateZExt(OffsetValue, SizeTy);
339 else
340 OffsetValue = ConstantInt::get(SizeTy, Offset);
341
342 if (SizeValue)
343 SizeValue = Builder->CreateZExt(SizeValue, SizeTy);
344 else
345 SizeValue = ConstantInt::get(SizeTy, Size);
346
347 Value *NeededSizeVal = ConstantInt::get(SizeTy, NeededSize);
348 Value *ObjSize = Builder->CreateSub(SizeValue, OffsetValue);
349 Value *Cmp1 = Builder->CreateICmpULT(SizeValue, OffsetValue);
350 Value *Cmp2 = Builder->CreateICmpULT(ObjSize, NeededSizeVal);
351 Value *Or = Builder->CreateOr(Cmp1, Cmp2);
Nuno Lopes2b526302012-05-23 16:24:52 +0000352 emitBranchToTrap(Or);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000353
Nuno Lopes5c525b52012-05-22 17:19:09 +0000354 ++ChecksAdded;
355 return true;
356}
357
358bool BoundsChecking::runOnFunction(Function &F) {
359 TD = &getAnalysis<TargetData>();
360
361 TrapBB = 0;
362 Fn = &F;
363 BuilderTy TheBuilder(F.getContext(), TargetFolder(TD));
364 Builder = &TheBuilder;
365
366 // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory
367 // touching instructions
368 std::vector<Instruction*> WorkList;
369 for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
370 Instruction *I = &*i;
371 if (isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) ||
372 isa<AtomicRMWInst>(I))
373 WorkList.push_back(I);
374 }
375
376 bool MadeChange = false;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000377 for (std::vector<Instruction*>::iterator i = WorkList.begin(),
378 e = WorkList.end(); i != e; ++i) {
379 Instruction *I = *i;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000380
381 Builder->SetInsertPoint(I);
382 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
383 MadeChange |= instrument(LI->getPointerOperand(), LI);
384 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
385 MadeChange |= instrument(SI->getPointerOperand(), SI->getValueOperand());
386 } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(I)) {
387 MadeChange |= instrument(AI->getPointerOperand(),AI->getCompareOperand());
388 } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(I)) {
389 MadeChange |= instrument(AI->getPointerOperand(), AI->getValOperand());
390 } else {
391 llvm_unreachable("unknown Instruction type");
392 }
393 }
394 return MadeChange;
395}
396
397FunctionPass *llvm::createBoundsCheckingPass(unsigned Penalty) {
398 return new BoundsChecking(Penalty);
399}