blob: 52089cb37b28fe8b57bb52c047feb55861ed8fe3 [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:
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000030 void checkLocation(SVal l, bool isLoad, CheckerContext &C) const;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000031};
32}
33
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000034void ArrayBoundChecker::checkLocation(SVal l, bool isLoad,
35 CheckerContext &C) const {
Zhongxing Xu58e689f2009-11-11 12:33:27 +000036 // Check for out of bound array element access.
37 const MemRegion *R = l.getAsRegion();
38 if (!R)
39 return;
40
Zhongxing Xu58e689f2009-11-11 12:33:27 +000041 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
42 if (!ER)
43 return;
44
45 // Get the index of the accessed element.
Gabor Greif89b06582010-09-09 10:51:37 +000046 DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000047
Zhongxing Xu110eaf12010-11-26 09:14:07 +000048 // Zero index is always in bound, this also passes ElementRegions created for
49 // pointer casts.
50 if (Idx.isZeroConstant())
51 return;
52
Ted Kremenek18c66fd2011-08-15 22:09:50 +000053 const ProgramState *state = C.getState();
Zhongxing Xu58e689f2009-11-11 12:33:27 +000054
55 // Get the size of the array.
Zhongxing Xue884ff82009-11-12 02:48:32 +000056 DefinedOrUnknownSVal NumElements
Zhongxing Xu3ed04d32010-01-18 08:54:31 +000057 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
Zhongxing Xu018220c2010-08-11 06:10:55 +000058 ER->getValueType());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000059
Ted Kremenek18c66fd2011-08-15 22:09:50 +000060 const ProgramState *StInBound = state->assumeInBound(Idx, NumElements, true);
61 const ProgramState *StOutBound = state->assumeInBound(Idx, NumElements, false);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000062 if (StOutBound && !StInBound) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +000063 ExplodedNode *N = C.generateSink(StOutBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000064 if (!N)
65 return;
66
67 if (!BT)
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000068 BT.reset(new BuiltinBug("Out-of-bound array access",
69 "Access out-of-bound array element (buffer overflow)"));
Zhongxing Xu58e689f2009-11-11 12:33:27 +000070
71 // FIXME: It would be nice to eventually make this diagnostic more clear,
72 // e.g., by referencing the original declaration or by saying *why* this
73 // reference is outside the range.
74
75 // Generate a report for this bug.
76 RangedBugReport *report =
Benjamin Kramerd02e2322009-11-14 12:08:24 +000077 new RangedBugReport(*BT, BT->getDescription(), N);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000078
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000079 report->addRange(C.getStmt()->getSourceRange());
Zhongxing Xu58e689f2009-11-11 12:33:27 +000080 C.EmitReport(report);
Ted Kremenekc3120762009-11-23 23:23:26 +000081 return;
Zhongxing Xu58e689f2009-11-11 12:33:27 +000082 }
Ted Kremenekc3120762009-11-23 23:23:26 +000083
84 // Array bound check succeeded. From this point forward the array bound
85 // should always succeed.
86 assert(StInBound);
87 C.addTransition(StInBound);
Zhongxing Xu58e689f2009-11-11 12:33:27 +000088}
Argyrios Kyrtzidis8be5b3a2011-02-24 08:42:12 +000089
90void ento::registerArrayBoundChecker(CheckerManager &mgr) {
91 mgr.registerChecker<ArrayBoundChecker>();
92}