don't use #pragma mark, it isn't portable.
[clang.git] / lib / StaticAnalyzer / EntoSA / Checkers / ArrayBoundChecker.cpp
blob13e628bcb1a56d32565a52e6c9bbc282eaedf4b8
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.
13 //===----------------------------------------------------------------------===//
15 #include "ExprEngineInternalChecks.h"
16 #include "clang/StaticAnalyzer/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
18 #include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
20 using namespace clang;
21 using namespace ento;
23 namespace {
24 class ArrayBoundChecker :
25 public CheckerVisitor<ArrayBoundChecker> {
26 BuiltinBug *BT;
27 public:
28 ArrayBoundChecker() : BT(0) {}
29 static void *getTag() { static int x = 0; return &x; }
30 void visitLocation(CheckerContext &C, const Stmt *S, SVal l);
34 void ento::RegisterArrayBoundChecker(ExprEngine &Eng) {
35 Eng.registerCheck(new ArrayBoundChecker());
38 void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l){
39 // Check for out of bound array element access.
40 const MemRegion *R = l.getAsRegion();
41 if (!R)
42 return;
44 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
45 if (!ER)
46 return;
48 // Get the index of the accessed element.
49 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
51 // Zero index is always in bound, this also passes ElementRegions created for
52 // pointer casts.
53 if (Idx.isZeroConstant())
54 return;
56 const GRState *state = C.getState();
58 // Get the size of the array.
59 DefinedOrUnknownSVal NumElements
60 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
61 ER->getValueType());
63 const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
64 const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
65 if (StOutBound && !StInBound) {
66 ExplodedNode *N = C.generateSink(StOutBound);
67 if (!N)
68 return;
70 if (!BT)
71 BT = new BuiltinBug("Out-of-bound array access",
72 "Access out-of-bound array element (buffer overflow)");
74 // FIXME: It would be nice to eventually make this diagnostic more clear,
75 // e.g., by referencing the original declaration or by saying *why* this
76 // reference is outside the range.
78 // Generate a report for this bug.
79 RangedBugReport *report =
80 new RangedBugReport(*BT, BT->getDescription(), N);
82 report->addRange(S->getSourceRange());
83 C.EmitReport(report);
84 return;
87 // Array bound check succeeded. From this point forward the array bound
88 // should always succeed.
89 assert(StInBound);
90 C.addTransition(StInBound);