blob: cb5b01009f1d9546c1f0b642831f6ecf529551bf [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 Kyrtzidis8be5b3a2011-02-24 08:42:12 +000015#include "ClangSACheckers.h"
Chandler Carruth55fc8732012-12-04 09:13:33 +000016#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000017#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000018#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000020#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
Zhongxing Xu58e689f2009-11-11 12:33:27 +000021
22using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000023using namespace ento;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000024
25namespace {
Kovarththanan Rajaratnamba5fb5a2009-11-28 06:07:30 +000026class ArrayBoundChecker :
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000027 public Checker<check::Location> {
Stephen Hines651f13c2014-04-23 16:59:28 -070028 mutable std::unique_ptr<BuiltinBug> BT;
29
Zhongxing Xu58e689f2009-11-11 12:33:27 +000030public:
Anna Zaks390909c2011-10-06 00:43:15 +000031 void checkLocation(SVal l, bool isLoad, const Stmt* S,
32 CheckerContext &C) const;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000033};
34}
35
Anna Zaks390909c2011-10-06 00:43:15 +000036void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000037 CheckerContext &C) const {
Zhongxing Xu58e689f2009-11-11 12:33:27 +000038 // Check for out of bound array element access.
39 const MemRegion *R = l.getAsRegion();
40 if (!R)
41 return;
42
Zhongxing Xu58e689f2009-11-11 12:33:27 +000043 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
44 if (!ER)
45 return;
46
47 // Get the index of the accessed element.
David Blaikie7a95de62013-02-21 22:23:56 +000048 DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
Zhongxing Xu58e689f2009-11-11 12:33:27 +000049
Zhongxing Xu110eaf12010-11-26 09:14:07 +000050 // Zero index is always in bound, this also passes ElementRegions created for
51 // pointer casts.
52 if (Idx.isZeroConstant())
53 return;
54
Ted Kremenek8bef8232012-01-26 21:29:00 +000055 ProgramStateRef state = C.getState();
Zhongxing Xu58e689f2009-11-11 12:33:27 +000056
57 // Get the size of the array.
Zhongxing Xue884ff82009-11-12 02:48:32 +000058 DefinedOrUnknownSVal NumElements
Zhongxing Xu3ed04d32010-01-18 08:54:31 +000059 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
Zhongxing Xu018220c2010-08-11 06:10:55 +000060 ER->getValueType());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000061
Ted Kremenek8bef8232012-01-26 21:29:00 +000062 ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
63 ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000064 if (StOutBound && !StInBound) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +000065 ExplodedNode *N = C.generateSink(StOutBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000066 if (!N)
67 return;
68
69 if (!BT)
Stephen Hines651f13c2014-04-23 16:59:28 -070070 BT.reset(new BuiltinBug(
71 this, "Out-of-bound array access",
72 "Access out-of-bound array element (buffer overflow)"));
Zhongxing Xu58e689f2009-11-11 12:33:27 +000073
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.
77
78 // Generate a report for this bug.
Anna Zakse172e8b2011-08-17 23:00:25 +000079 BugReport *report =
80 new BugReport(*BT, BT->getDescription(), N);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000081
Anna Zaks390909c2011-10-06 00:43:15 +000082 report->addRange(LoadS->getSourceRange());
Jordan Rose785950e2012-11-02 01:53:40 +000083 C.emitReport(report);
Ted Kremenekc3120762009-11-23 23:23:26 +000084 return;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000085 }
Ted Kremenekc3120762009-11-23 23:23:26 +000086
87 // Array bound check succeeded. From this point forward the array bound
88 // should always succeed.
Anna Zaks0bd6b112011-10-26 21:06:34 +000089 C.addTransition(StInBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000090}
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000091
92void ento::registerArrayBoundChecker(CheckerManager &mgr) {
93 mgr.registerChecker<ArrayBoundChecker>();
94}