1*67e74705SXin Li //== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This file defines ArrayBoundChecker, which is a path-sensitive check
11*67e74705SXin Li // which looks for an out-of-bound array element access.
12*67e74705SXin Li //
13*67e74705SXin Li //===----------------------------------------------------------------------===//
14*67e74705SXin Li
15*67e74705SXin Li #include "ClangSACheckers.h"
16*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
18*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
21*67e74705SXin Li
22*67e74705SXin Li using namespace clang;
23*67e74705SXin Li using namespace ento;
24*67e74705SXin Li
25*67e74705SXin Li namespace {
26*67e74705SXin Li class ArrayBoundChecker :
27*67e74705SXin Li public Checker<check::Location> {
28*67e74705SXin Li mutable std::unique_ptr<BuiltinBug> BT;
29*67e74705SXin Li
30*67e74705SXin Li public:
31*67e74705SXin Li void checkLocation(SVal l, bool isLoad, const Stmt* S,
32*67e74705SXin Li CheckerContext &C) const;
33*67e74705SXin Li };
34*67e74705SXin Li }
35*67e74705SXin Li
checkLocation(SVal l,bool isLoad,const Stmt * LoadS,CheckerContext & C) const36*67e74705SXin Li void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
37*67e74705SXin Li CheckerContext &C) const {
38*67e74705SXin Li // Check for out of bound array element access.
39*67e74705SXin Li const MemRegion *R = l.getAsRegion();
40*67e74705SXin Li if (!R)
41*67e74705SXin Li return;
42*67e74705SXin Li
43*67e74705SXin Li const ElementRegion *ER = dyn_cast<ElementRegion>(R);
44*67e74705SXin Li if (!ER)
45*67e74705SXin Li return;
46*67e74705SXin Li
47*67e74705SXin Li // Get the index of the accessed element.
48*67e74705SXin Li DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
49*67e74705SXin Li
50*67e74705SXin Li // Zero index is always in bound, this also passes ElementRegions created for
51*67e74705SXin Li // pointer casts.
52*67e74705SXin Li if (Idx.isZeroConstant())
53*67e74705SXin Li return;
54*67e74705SXin Li
55*67e74705SXin Li ProgramStateRef state = C.getState();
56*67e74705SXin Li
57*67e74705SXin Li // Get the size of the array.
58*67e74705SXin Li DefinedOrUnknownSVal NumElements
59*67e74705SXin Li = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
60*67e74705SXin Li ER->getValueType());
61*67e74705SXin Li
62*67e74705SXin Li ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
63*67e74705SXin Li ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
64*67e74705SXin Li if (StOutBound && !StInBound) {
65*67e74705SXin Li ExplodedNode *N = C.generateErrorNode(StOutBound);
66*67e74705SXin Li if (!N)
67*67e74705SXin Li return;
68*67e74705SXin Li
69*67e74705SXin Li if (!BT)
70*67e74705SXin Li BT.reset(new BuiltinBug(
71*67e74705SXin Li this, "Out-of-bound array access",
72*67e74705SXin Li "Access out-of-bound array element (buffer overflow)"));
73*67e74705SXin Li
74*67e74705SXin Li // FIXME: It would be nice to eventually make this diagnostic more clear,
75*67e74705SXin Li // e.g., by referencing the original declaration or by saying *why* this
76*67e74705SXin Li // reference is outside the range.
77*67e74705SXin Li
78*67e74705SXin Li // Generate a report for this bug.
79*67e74705SXin Li auto report = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);
80*67e74705SXin Li
81*67e74705SXin Li report->addRange(LoadS->getSourceRange());
82*67e74705SXin Li C.emitReport(std::move(report));
83*67e74705SXin Li return;
84*67e74705SXin Li }
85*67e74705SXin Li
86*67e74705SXin Li // Array bound check succeeded. From this point forward the array bound
87*67e74705SXin Li // should always succeed.
88*67e74705SXin Li C.addTransition(StInBound);
89*67e74705SXin Li }
90*67e74705SXin Li
registerArrayBoundChecker(CheckerManager & mgr)91*67e74705SXin Li void ento::registerArrayBoundChecker(CheckerManager &mgr) {
92*67e74705SXin Li mgr.registerChecker<ArrayBoundChecker>();
93*67e74705SXin Li }
94