blob: 85c5e111e0ff3b1ad567a5fa2d5f462606e32e2e [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"
29#include "llvm/Operator.h"
30#include "llvm/Pass.h"
31using namespace llvm;
32
33STATISTIC(ChecksAdded, "Bounds checks added");
34STATISTIC(ChecksSkipped, "Bounds checks skipped");
35STATISTIC(ChecksUnable, "Bounds checks unable to add");
36
37typedef IRBuilder<true, TargetFolder> BuilderTy;
38
39namespace {
40 enum ConstTriState {
41 NotConst, Const, Dunno
42 };
43
44 struct BoundsChecking : public FunctionPass {
Nuno Lopes5c525b52012-05-22 17:19:09 +000045 static char ID;
46
47 BoundsChecking(unsigned _Penalty = 5) : FunctionPass(ID), Penalty(_Penalty){
48 initializeBoundsCheckingPass(*PassRegistry::getPassRegistry());
49 }
50
Nuno Lopes5c525b52012-05-22 17:19:09 +000051 virtual bool runOnFunction(Function &F);
52
53 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
54 AU.addRequired<TargetData>();
55 }
Nuno Lopes2f0a7482012-05-22 22:02:19 +000056
57 private:
58 const TargetData *TD;
59 BuilderTy *Builder;
60 Function *Fn;
61 BasicBlock *TrapBB;
62 unsigned Penalty;
63
64 BasicBlock *getTrapBB();
Nuno Lopes2b526302012-05-23 16:24:52 +000065 void emitBranchToTrap(Value *Cmp = 0);
Nuno Lopes2f0a7482012-05-22 22:02:19 +000066 ConstTriState computeAllocSize(Value *Alloc, uint64_t &Size,
67 Value* &SizeValue);
68 bool instrument(Value *Ptr, Value *Val);
Nuno Lopes5c525b52012-05-22 17:19:09 +000069 };
70}
71
72char BoundsChecking::ID = 0;
73INITIALIZE_PASS(BoundsChecking, "bounds-checking", "Run-time bounds checking",
74 false, false)
75
76
77/// getTrapBB - create a basic block that traps. All overflowing conditions
78/// branch to this block. There's only one trap block per function.
79BasicBlock *BoundsChecking::getTrapBB() {
80 if (TrapBB)
81 return TrapBB;
82
83 BasicBlock::iterator PrevInsertPoint = Builder->GetInsertPoint();
84 TrapBB = BasicBlock::Create(Fn->getContext(), "trap", Fn);
85 Builder->SetInsertPoint(TrapBB);
86
87 llvm::Value *F = Intrinsic::getDeclaration(Fn->getParent(), Intrinsic::trap);
88 CallInst *TrapCall = Builder->CreateCall(F);
89 TrapCall->setDoesNotReturn();
90 TrapCall->setDoesNotThrow();
91 Builder->CreateUnreachable();
92
93 Builder->SetInsertPoint(PrevInsertPoint);
94 return TrapBB;
95}
96
97
Nuno Lopes2b526302012-05-23 16:24:52 +000098/// emitBranchToTrap - emit a branch instruction to a trap block.
99/// If Cmp is non-null, perform a jump only if its value evaluates to true.
100void BoundsChecking::emitBranchToTrap(Value *Cmp) {
101 Instruction *Inst = Builder->GetInsertPoint();
102 BasicBlock *OldBB = Inst->getParent();
103 BasicBlock *Cont = OldBB->splitBasicBlock(Inst);
104 OldBB->getTerminator()->eraseFromParent();
105
106 // FIXME: add unlikely branch taken metadata?
107 if (Cmp)
108 BranchInst::Create(getTrapBB(), Cont, Cmp, OldBB);
109 else
110 BranchInst::Create(getTrapBB(), OldBB);
111}
112
113
Nuno Lopes5c525b52012-05-22 17:19:09 +0000114/// computeAllocSize - compute the object size allocated by an allocation
115/// site. Returns NotConst if the size is not constant (in SizeValue), Const if
116/// the size is constant (in Size), and Dunno if the size could not be
117/// determined within the given maximum Penalty that the computation would
118/// incurr at run-time.
119ConstTriState BoundsChecking::computeAllocSize(Value *Alloc, uint64_t &Size,
120 Value* &SizeValue) {
121 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Alloc)) {
122 if (GV->hasDefinitiveInitializer()) {
123 Constant *C = GV->getInitializer();
124 Size = TD->getTypeAllocSize(C->getType());
125 return Const;
126 }
127 return Dunno;
128
129 } else if (AllocaInst *AI = dyn_cast<AllocaInst>(Alloc)) {
130 if (!AI->getAllocatedType()->isSized())
131 return Dunno;
132
133 Size = TD->getTypeAllocSize(AI->getAllocatedType());
134 if (!AI->isArrayAllocation())
135 return Const; // we are done
136
137 Value *ArraySize = AI->getArraySize();
138 if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
139 Size *= C->getZExtValue();
140 return Const;
141 }
142
143 if (Penalty < 2)
144 return Dunno;
145
146 SizeValue = ConstantInt::get(ArraySize->getType(), Size);
147 SizeValue = Builder->CreateMul(SizeValue, ArraySize);
148 return NotConst;
149
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000150 } else if (CallInst *CI = dyn_cast<CallInst>(Alloc)) {
151 Function *Callee = CI->getCalledFunction();
152 if (!Callee || !Callee->isDeclaration())
Nuno Lopes5c525b52012-05-22 17:19:09 +0000153 return Dunno;
154
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000155 FunctionType *FTy = Callee->getFunctionType();
156 if (FTy->getNumParams() == 1) {
157 // alloc(size)
158 if ((FTy->getParamType(0)->isIntegerTy(32) ||
159 FTy->getParamType(0)->isIntegerTy(64)) &&
160 (Callee->getName() == "malloc" ||
161 Callee->getName() == "valloc" ||
162 Callee->getName() == "_Znwj" || // operator new(unsigned int)
163 Callee->getName() == "_Znwm" || // operator new(unsigned long)
164 Callee->getName() == "_Znaj" || // operator new[](unsigned int)
165 Callee->getName() == "_Znam")) { // operator new[](unsigned long)
166 SizeValue = CI->getArgOperand(0);
167 if (ConstantInt *Arg = dyn_cast<ConstantInt>(SizeValue)) {
168 Size = Arg->getZExtValue();
169 return Const;
170 }
171 return Penalty >= 2 ? NotConst : Dunno;
172 }
173 return Dunno;
174 }
175
176 if (FTy->getNumParams() == 2) {
177 // alloc(x, y) and return buffer of size x * y
178 if (((FTy->getParamType(0)->isIntegerTy(32) &&
179 FTy->getParamType(1)->isIntegerTy(32)) ||
180 (FTy->getParamType(0)->isIntegerTy(64) &&
181 FTy->getParamType(1)->isIntegerTy(64))) &&
182 Callee->getName() == "calloc") {
183 Value *Arg1 = CI->getArgOperand(0);
184 Value *Arg2 = CI->getArgOperand(1);
185 if (ConstantInt *CI1 = dyn_cast<ConstantInt>(Arg1)) {
186 if (ConstantInt *CI2 = dyn_cast<ConstantInt>(Arg2)) {
187 Size = (CI1->getValue() * CI2->getValue()).getZExtValue();
188 return Const;
189 }
190 }
191
192 if (Penalty < 2)
193 return Dunno;
194
195 SizeValue = Builder->CreateMul(Arg1, Arg2);
196 return NotConst;
197 }
198
199 // realloc(ptr, size)
200 if ((FTy->getParamType(1)->isIntegerTy(32) ||
201 FTy->getParamType(1)->isIntegerTy(64)) &&
202 (Callee->getName() == "realloc" ||
203 Callee->getName() == "reallocf")) {
204 SizeValue = CI->getArgOperand(1);
205 if (ConstantInt *Arg = dyn_cast<ConstantInt>(SizeValue)) {
206 Size = Arg->getZExtValue();
207 return Const;
208 }
209 return Penalty >= 2 ? NotConst : Dunno;
210 }
211 }
212 // TODO: handle more standard functions:
213 // - strdup / strndup
214 // - strcpy / strncpy
215 // - memcpy / memmove
216 // - strcat / strncat
Nuno Lopes5c525b52012-05-22 17:19:09 +0000217 }
218
219 DEBUG(dbgs() << "computeAllocSize failed:\n" << *Alloc);
220 return Dunno;
221}
222
223
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000224/// instrument - adds run-time bounds checks to memory accessing instructions.
225/// Ptr is the pointer that will be read/written, and InstVal is either the
226/// result from the load or the value being stored. It is used to determine the
227/// size of memory block that is touched.
228/// Returns true if any change was made to the IR, false otherwise.
Nuno Lopes5c525b52012-05-22 17:19:09 +0000229bool BoundsChecking::instrument(Value *Ptr, Value *InstVal) {
230 uint64_t NeededSize = TD->getTypeStoreSize(InstVal->getType());
231 DEBUG(dbgs() << "Instrument " << *Ptr << " for " << Twine(NeededSize)
232 << " bytes\n");
233
234 Type *SizeTy = Type::getInt64Ty(Fn->getContext());
235
236 // Get to the real allocated thing and offset as fast as possible.
237 Ptr = Ptr->stripPointerCasts();
238 GEPOperator *GEP;
239
240 if ((GEP = dyn_cast<GEPOperator>(Ptr))) {
241 // check if we will be able to get the offset
242 if (!GEP->hasAllConstantIndices() && Penalty < 2) {
243 ++ChecksUnable;
244 return false;
245 }
246 Ptr = GEP->getPointerOperand()->stripPointerCasts();
247 }
248
249 uint64_t Size = 0;
250 Value *SizeValue = 0;
251 ConstTriState ConstAlloc = computeAllocSize(Ptr, Size, SizeValue);
252 if (ConstAlloc == Dunno) {
253 ++ChecksUnable;
254 return false;
255 }
256 assert(ConstAlloc == Const || SizeValue);
257
258 uint64_t Offset = 0;
259 Value *OffsetValue = 0;
260
261 if (GEP) {
262 if (GEP->hasAllConstantIndices()) {
263 SmallVector<Value*, 8> Ops(GEP->idx_begin(), GEP->idx_end());
264 assert(GEP->getPointerOperandType()->isPointerTy());
265 Offset = TD->getIndexedOffset(GEP->getPointerOperandType(), Ops);
266 } else {
267 OffsetValue = EmitGEPOffset(Builder, *TD, GEP);
268 }
269 }
270
271 if (!OffsetValue && ConstAlloc == Const) {
272 if (Size < Offset || (Size - Offset) < NeededSize) {
273 // Out of bounds
Nuno Lopes2b526302012-05-23 16:24:52 +0000274 emitBranchToTrap();
Nuno Lopes5c525b52012-05-22 17:19:09 +0000275 ++ChecksAdded;
276 return true;
277 }
278 // in bounds
279 ++ChecksSkipped;
280 return false;
281 }
282
283 if (OffsetValue)
284 OffsetValue = Builder->CreateZExt(OffsetValue, SizeTy);
285 else
286 OffsetValue = ConstantInt::get(SizeTy, Offset);
287
288 if (SizeValue)
289 SizeValue = Builder->CreateZExt(SizeValue, SizeTy);
290 else
291 SizeValue = ConstantInt::get(SizeTy, Size);
292
293 Value *NeededSizeVal = ConstantInt::get(SizeTy, NeededSize);
294 Value *ObjSize = Builder->CreateSub(SizeValue, OffsetValue);
295 Value *Cmp1 = Builder->CreateICmpULT(SizeValue, OffsetValue);
296 Value *Cmp2 = Builder->CreateICmpULT(ObjSize, NeededSizeVal);
297 Value *Or = Builder->CreateOr(Cmp1, Cmp2);
Nuno Lopes2b526302012-05-23 16:24:52 +0000298 emitBranchToTrap(Or);
Nuno Lopes5c525b52012-05-22 17:19:09 +0000299
Nuno Lopes5c525b52012-05-22 17:19:09 +0000300 ++ChecksAdded;
301 return true;
302}
303
304bool BoundsChecking::runOnFunction(Function &F) {
305 TD = &getAnalysis<TargetData>();
306
307 TrapBB = 0;
308 Fn = &F;
309 BuilderTy TheBuilder(F.getContext(), TargetFolder(TD));
310 Builder = &TheBuilder;
311
312 // check HANDLE_MEMORY_INST in include/llvm/Instruction.def for memory
313 // touching instructions
314 std::vector<Instruction*> WorkList;
315 for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
316 Instruction *I = &*i;
317 if (isa<LoadInst>(I) || isa<StoreInst>(I) || isa<AtomicCmpXchgInst>(I) ||
318 isa<AtomicRMWInst>(I))
319 WorkList.push_back(I);
320 }
321
322 bool MadeChange = false;
Nuno Lopes2f0a7482012-05-22 22:02:19 +0000323 for (std::vector<Instruction*>::iterator i = WorkList.begin(),
324 e = WorkList.end(); i != e; ++i) {
325 Instruction *I = *i;
Nuno Lopes5c525b52012-05-22 17:19:09 +0000326
327 Builder->SetInsertPoint(I);
328 if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
329 MadeChange |= instrument(LI->getPointerOperand(), LI);
330 } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
331 MadeChange |= instrument(SI->getPointerOperand(), SI->getValueOperand());
332 } else if (AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(I)) {
333 MadeChange |= instrument(AI->getPointerOperand(),AI->getCompareOperand());
334 } else if (AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(I)) {
335 MadeChange |= instrument(AI->getPointerOperand(), AI->getValOperand());
336 } else {
337 llvm_unreachable("unknown Instruction type");
338 }
339 }
340 return MadeChange;
341}
342
343FunctionPass *llvm::createBoundsCheckingPass(unsigned Penalty) {
344 return new BoundsChecking(Penalty);
345}