blob: 535d8eede46ab1d5674b661b0203a9ec446ca5c9 [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"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000016#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidisdd407f42011-02-24 08:42:12 +000017#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenekf8cbac42011-02-10 01:03:03 +000019#include "clang/StaticAnalyzer/Core/BugReporter/BugType.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> {
Dylan Noblesmithe2778992012-02-05 02:12:40 +000028 mutable OwningPtr<BuiltinBug> BT;
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000029public:
Anna Zaks3e0f4152011-10-06 00:43:15 +000030 void checkLocation(SVal l, bool isLoad, const Stmt* S,
31 CheckerContext &C) const;
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000032};
33}
34
Anna Zaks3e0f4152011-10-06 00:43:15 +000035void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
Argyrios Kyrtzidisdd407f42011-02-24 08:42:12 +000036 CheckerContext &C) const {
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000037 // Check for out of bound array element access.
38 const MemRegion *R = l.getAsRegion();
39 if (!R)
40 return;
41
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000042 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
43 if (!ER)
44 return;
45
46 // Get the index of the accessed element.
Gabor Greif230ddf32010-09-09 10:51:37 +000047 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000048
Zhongxing Xue1e85652010-11-26 09:14:07 +000049 // Zero index is always in bound, this also passes ElementRegions created for
50 // pointer casts.
51 if (Idx.isZeroConstant())
52 return;
53
Ted Kremenek49b1e382012-01-26 21:29:00 +000054 ProgramStateRef state = C.getState();
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000055
56 // Get the size of the array.
Zhongxing Xu383c2732009-11-12 02:48:32 +000057 DefinedOrUnknownSVal NumElements
Zhongxing Xu228b0d42010-01-18 08:54:31 +000058 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
Zhongxing Xu8de0a3d2010-08-11 06:10:55 +000059 ER->getValueType());
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000060
Ted Kremenek49b1e382012-01-26 21:29:00 +000061 ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
62 ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000063 if (StOutBound && !StInBound) {
Ted Kremenek750b7ac2010-12-20 21:19:09 +000064 ExplodedNode *N = C.generateSink(StOutBound);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000065 if (!N)
66 return;
67
68 if (!BT)
Argyrios Kyrtzidisdd407f42011-02-24 08:42:12 +000069 BT.reset(new BuiltinBug("Out-of-bound array access",
70 "Access out-of-bound array element (buffer overflow)"));
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000071
72 // FIXME: It would be nice to eventually make this diagnostic more clear,
73 // e.g., by referencing the original declaration or by saying *why* this
74 // reference is outside the range.
75
76 // Generate a report for this bug.
Anna Zaks3a6bdf82011-08-17 23:00:25 +000077 BugReport *report =
78 new BugReport(*BT, BT->getDescription(), N);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000079
Anna Zaks3e0f4152011-10-06 00:43:15 +000080 report->addRange(LoadS->getSourceRange());
Jordan Rosee10d5a72012-11-02 01:53:40 +000081 C.emitReport(report);
Ted Kremenekb0c0b082009-11-23 23:23:26 +000082 return;
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000083 }
Ted Kremenekb0c0b082009-11-23 23:23:26 +000084
85 // Array bound check succeeded. From this point forward the array bound
86 // should always succeed.
Anna Zaksda4c8d62011-10-26 21:06:34 +000087 C.addTransition(StInBound);
Zhongxing Xu4f7759a2009-11-11 12:33:27 +000088}
Argyrios Kyrtzidisdd407f42011-02-24 08:42:12 +000089
90void ento::registerArrayBoundChecker(CheckerManager &mgr) {
91 mgr.registerChecker<ArrayBoundChecker>();
92}