blob: cb5b01009f1d9546c1f0b642831f6ecf529551bf [file] [log] [blame]
Zhongxing Xu4f7759a2009-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 Kyrtzidisdd407f42011-02-24 08:42:12 +000015#include "ClangSACheckers.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000016#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000017#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidisdd407f42011-02-24 08:42:12 +000018#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000020#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000021
22using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000023using namespace ento;
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000024
25namespace {
Kovarththanan Rajaratnam65c65662009-11-28 06:07:30 +000026class ArrayBoundChecker :
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000027 public Checker<check::Location> {
Ahmed Charlesb8984322014-03-07 20:03:18 +000028 mutable std::unique_ptr<BuiltinBug> BT;
29
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000030public:
Anna Zaks3e0f4152011-10-06 00:43:15 +000031 void checkLocation(SVal l, bool isLoad, const Stmt* S,
32 CheckerContext &C) const;
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000033};
34}
35
Anna Zaks3e0f4152011-10-06 00:43:15 +000036void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
Argyrios Kyrtzidisdd407f42011-02-24 08:42:12 +000037 CheckerContext &C) const {
Zhongxing Xu4f7759a2009-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 Xu4f7759a2009-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 Blaikie87396b92013-02-21 22:23:56 +000048 DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000049
Zhongxing Xue1e85652010-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 Kremenek49b1e382012-01-26 21:29:00 +000055 ProgramStateRef state = C.getState();
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000056
57 // Get the size of the array.
Zhongxing Xu383c2732009-11-12 02:48:32 +000058 DefinedOrUnknownSVal NumElements
Zhongxing Xu228b0d42010-01-18 08:54:31 +000059 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +000060 ER->getValueType());
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000061
Ted Kremenek49b1e382012-01-26 21:29:00 +000062 ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
63 ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000064 if (StOutBound && !StInBound) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +000065 ExplodedNode *N = C.generateSink(StOutBound);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000066 if (!N)
67 return;
68
69 if (!BT)
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000070 BT.reset(new BuiltinBug(
71 this, "Out-of-bound array access",
72 "Access out-of-bound array element (buffer overflow)"));
Zhongxing Xu4f7759a2009-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 Zaks3a6bdf82011-08-17 23:00:25 +000079 BugReport *report =
80 new BugReport(*BT, BT->getDescription(), N);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000081
Anna Zaks3e0f4152011-10-06 00:43:15 +000082 report->addRange(LoadS->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +000083 C.emitReport(report);
Ted Kremenekb0c0b082009-11-23 23:23:26 +000084 return;
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000085 }
Ted Kremenekb0c0b082009-11-23 23:23:26 +000086
87 // Array bound check succeeded. From this point forward the array bound
88 // should always succeed.
Anna Zaksda4c8d62011-10-26 21:06:34 +000089 C.addTransition(StInBound);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000090}
Argyrios Kyrtzidisdd407f42011-02-24 08:42:12 +000091
92void ento::registerArrayBoundChecker(CheckerManager &mgr) {
93 mgr.registerChecker<ArrayBoundChecker>();
94}