blob: 6935c5f1c19239e85927c5f66cd2e60d02295936 [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"
Argyrios Kyrtzidisec8605f2011-03-01 01:16:21 +000016#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000017#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000019#include "clang/StaticAnalyzer/Core/BugReporter/BugType.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> {
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000028 mutable llvm::OwningPtr<BuiltinBug> BT;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000029public:
Anna Zaks390909c2011-10-06 00:43:15 +000030 void checkLocation(SVal l, bool isLoad, const Stmt* S,
31 CheckerContext &C) const;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000032};
33}
34
Anna Zaks390909c2011-10-06 00:43:15 +000035void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000036 CheckerContext &C) const {
Zhongxing Xu58e689f2009-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 Xu58e689f2009-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 Greif89b06582010-09-09 10:51:37 +000047 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000048
Zhongxing Xu110eaf12010-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 Kremenek18c66fd2011-08-15 22:09:50 +000054 const ProgramState *state = C.getState();
Zhongxing Xu58e689f2009-11-11 12:33:27 +000055
56 // Get the size of the array.
Zhongxing Xue884ff82009-11-12 02:48:32 +000057 DefinedOrUnknownSVal NumElements
Zhongxing Xu3ed04d32010-01-18 08:54:31 +000058 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
Zhongxing Xu018220c2010-08-11 06:10:55 +000059 ER->getValueType());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000060
Ted Kremenek18c66fd2011-08-15 22:09:50 +000061 const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true);
62 const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000063 if (StOutBound && !StInBound) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +000064 ExplodedNode *N = C.generateSink(StOutBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000065 if (!N)
66 return;
67
68 if (!BT)
Argyrios Kyrtzidis8be5b3a2011-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 Xu58e689f2009-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 Zakse172e8b2011-08-17 23:00:25 +000077 BugReport *report =
78 new BugReport(*BT, BT->getDescription(), N);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000079
Anna Zaks390909c2011-10-06 00:43:15 +000080 report->addRange(LoadS->getSourceRange());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000081 C.EmitReport(report);
Ted Kremenekc3120762009-11-23 23:23:26 +000082 return;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000083 }
Ted Kremenekc3120762009-11-23 23:23:26 +000084
85 // Array bound check succeeded. From this point forward the array bound
86 // should always succeed.
87 assert(StInBound);
88 C.addTransition(StInBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000089}
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000090
91void ento::registerArrayBoundChecker(CheckerManager &mgr) {
92 mgr.registerChecker<ArrayBoundChecker>();
93}