blob: 20d2b49137a705c1462e76b8dedd2a7f79b70bac [file] [log] [blame]
Zhongxing Xu58e689f2009-11-11 12:33:27 +00001//== 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
Argyrios Kyrtzidis04291a72011-02-08 22:30:02 +000015#include "InternalChecks.h"
Ted Kremenek21142582010-12-23 19:38:26 +000016#include "clang/StaticAnalyzer/BugReporter/BugType.h"
17#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
18#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
Zhongxing Xu58e689f2009-11-11 12:33:27 +000019
20using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000021using namespace ento;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000022
23namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000024class ArrayBoundChecker :
Zhongxing Xu58e689f2009-11-11 12:33:27 +000025 public CheckerVisitor<ArrayBoundChecker> {
26 BuiltinBug *BT;
27public:
Ted Kremenek342e9072010-12-20 21:22:47 +000028 ArrayBoundChecker() : BT(0) {}
29 static void *getTag() { static int x = 0; return &x; }
Argyrios Kyrtzidisf7fbbda2011-01-11 19:45:13 +000030 void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000031};
32}
33
Ted Kremenek9ef65372010-12-23 07:20:52 +000034void ento::RegisterArrayBoundChecker(ExprEngine &Eng) {
Zhongxing Xu58e689f2009-11-11 12:33:27 +000035 Eng.registerCheck(new ArrayBoundChecker());
36}
37
Argyrios Kyrtzidisf7fbbda2011-01-11 19:45:13 +000038void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l,
39 bool isLoad) {
Zhongxing Xu58e689f2009-11-11 12:33:27 +000040 // Check for out of bound array element access.
41 const MemRegion *R = l.getAsRegion();
42 if (!R)
43 return;
44
Zhongxing Xu58e689f2009-11-11 12:33:27 +000045 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
46 if (!ER)
47 return;
48
49 // Get the index of the accessed element.
Gabor Greif89b06582010-09-09 10:51:37 +000050 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000051
Zhongxing Xu110eaf12010-11-26 09:14:07 +000052 // Zero index is always in bound, this also passes ElementRegions created for
53 // pointer casts.
54 if (Idx.isZeroConstant())
55 return;
56
Zhongxing Xu58e689f2009-11-11 12:33:27 +000057 const GRState *state = C.getState();
58
59 // Get the size of the array.
Zhongxing Xue884ff82009-11-12 02:48:32 +000060 DefinedOrUnknownSVal NumElements
Zhongxing Xu3ed04d32010-01-18 08:54:31 +000061 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
Zhongxing Xu018220c2010-08-11 06:10:55 +000062 ER->getValueType());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000063
Ted Kremenek28f47b92010-12-01 22:16:56 +000064 const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
65 const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000066 if (StOutBound && !StInBound) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +000067 ExplodedNode *N = C.generateSink(StOutBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000068 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 =
Benjamin Kramerd02e2322009-11-14 12:08:24 +000081 new RangedBugReport(*BT, BT->getDescription(), N);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000082
83 report->addRange(S->getSourceRange());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000084 C.EmitReport(report);
Ted Kremenekc3120762009-11-23 23:23:26 +000085 return;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000086 }
Ted Kremenekc3120762009-11-23 23:23:26 +000087
88 // Array bound check succeeded. From this point forward the array bound
89 // should always succeed.
90 assert(StInBound);
91 C.addTransition(StInBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000092}