ArrayBoundChecker.cpp revision 04291a7c76e16a2dc5433c80c3d13c826bf372dc
1//== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==// 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 defines ArrayBoundChecker, which is a path-sensitive check 11// which looks for an out-of-bound array element access. 12// 13//===----------------------------------------------------------------------===// 14 15#include "InternalChecks.h" 16#include "clang/StaticAnalyzer/BugReporter/BugType.h" 17#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h" 18#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h" 19 20using namespace clang; 21using namespace ento; 22 23namespace { 24class ArrayBoundChecker : 25 public CheckerVisitor<ArrayBoundChecker> { 26 BuiltinBug *BT; 27public: 28 ArrayBoundChecker() : BT(0) {} 29 static void *getTag() { static int x = 0; return &x; } 30 void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad); 31}; 32} 33 34void ento::RegisterArrayBoundChecker(ExprEngine &Eng) { 35 Eng.registerCheck(new ArrayBoundChecker()); 36} 37 38void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l, 39 bool isLoad) { 40 // Check for out of bound array element access. 41 const MemRegion *R = l.getAsRegion(); 42 if (!R) 43 return; 44 45 const ElementRegion *ER = dyn_cast<ElementRegion>(R); 46 if (!ER) 47 return; 48 49 // Get the index of the accessed element. 50 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); 51 52 // Zero index is always in bound, this also passes ElementRegions created for 53 // pointer casts. 54 if (Idx.isZeroConstant()) 55 return; 56 57 const GRState *state = C.getState(); 58 59 // Get the size of the array. 60 DefinedOrUnknownSVal NumElements 61 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 62 ER->getValueType()); 63 64 const GRState *StInBound = state->assumeInBound(Idx, NumElements, true); 65 const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false); 66 if (StOutBound && !StInBound) { 67 ExplodedNode *N = C.generateSink(StOutBound); 68 if (!N) 69 return; 70 71 if (!BT) 72 BT = new BuiltinBug("Out-of-bound array access", 73 "Access out-of-bound array element (buffer overflow)"); 74 75 // FIXME: It would be nice to eventually make this diagnostic more clear, 76 // e.g., by referencing the original declaration or by saying *why* this 77 // reference is outside the range. 78 79 // Generate a report for this bug. 80 RangedBugReport *report = 81 new RangedBugReport(*BT, BT->getDescription(), N); 82 83 report->addRange(S->getSourceRange()); 84 C.EmitReport(report); 85 return; 86 } 87 88 // Array bound check succeeded. From this point forward the array bound 89 // should always succeed. 90 assert(StInBound); 91 C.addTransition(StInBound); 92} 93