158e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==//
258e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//
358e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//                     The LLVM Compiler Infrastructure
458e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//
558e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu// This file is distributed under the University of Illinois Open Source
658e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu// License. See LICENSE.TXT for details.
758e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//
858e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//===----------------------------------------------------------------------===//
958e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//
1058e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu// This file defines ArrayBoundChecker, which is a path-sensitive check
1158e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu// which looks for an out-of-bound array element access.
1258e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//
1358e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu//===----------------------------------------------------------------------===//
1458e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
158be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidis#include "ClangSACheckers.h"
1655fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h"
188be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h"
198be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
2158e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
2258e689fead1490611bcd114fb707bfc08a12049eZhongxing Xuusing namespace clang;
239ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
2458e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
2558e689fead1490611bcd114fb707bfc08a12049eZhongxing Xunamespace {
26ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass ArrayBoundChecker :
27ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis    public Checker<check::Location> {
28651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  mutable std::unique_ptr<BuiltinBug> BT;
29651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
3058e689fead1490611bcd114fb707bfc08a12049eZhongxing Xupublic:
31390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks  void checkLocation(SVal l, bool isLoad, const Stmt* S,
32390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks                     CheckerContext &C) const;
3358e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu};
3458e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu}
3558e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
36390909c89c98ab1807e15e033a72e975f866fb23Anna Zaksvoid ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
378be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidis                                      CheckerContext &C) const {
3858e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  // Check for out of bound array element access.
3958e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  const MemRegion *R = l.getAsRegion();
4058e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  if (!R)
4158e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    return;
4258e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
4358e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  const ElementRegion *ER = dyn_cast<ElementRegion>(R);
4458e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  if (!ER)
4558e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    return;
4658e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
4758e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  // Get the index of the accessed element.
487a95de68c093991047ed8d339479ccad51b88663David Blaikie  DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
4958e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
50110eaf156121760073fe6af6b3b0ed09be0cc0ceZhongxing Xu  // Zero index is always in bound, this also passes ElementRegions created for
51110eaf156121760073fe6af6b3b0ed09be0cc0ceZhongxing Xu  // pointer casts.
52110eaf156121760073fe6af6b3b0ed09be0cc0ceZhongxing Xu  if (Idx.isZeroConstant())
53110eaf156121760073fe6af6b3b0ed09be0cc0ceZhongxing Xu    return;
54110eaf156121760073fe6af6b3b0ed09be0cc0ceZhongxing Xu
558bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef state = C.getState();
5658e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
5758e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  // Get the size of the array.
58e884ff88baa1bd61db273baf107862a2110058edZhongxing Xu  DefinedOrUnknownSVal NumElements
593ed04d37573c566205d965d2e91d54ccae898d0aZhongxing Xu    = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
60018220c343c103b7dfaa117a7a474c7a7fd6d068Zhongxing Xu                                            ER->getValueType());
6158e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
628bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
638bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek  ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false);
6458e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  if (StOutBound && !StInBound) {
65d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek    ExplodedNode *N = C.generateSink(StOutBound);
6658e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    if (!N)
6758e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu      return;
6858e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
6958e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    if (!BT)
70651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      BT.reset(new BuiltinBug(
71651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          this, "Out-of-bound array access",
72651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          "Access out-of-bound array element (buffer overflow)"));
7358e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
7458e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    // FIXME: It would be nice to eventually make this diagnostic more clear,
7558e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    // e.g., by referencing the original declaration or by saying *why* this
7658e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    // reference is outside the range.
7758e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
7858e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu    // Generate a report for this bug.
79e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks    BugReport *report =
80e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks      new BugReport(*BT, BT->getDescription(), N);
8158e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu
82390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks    report->addRange(LoadS->getSourceRange());
83785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose    C.emitReport(report);
84c3120769b3b5b3d86fd7bf83fbff8fb60369c213Ted Kremenek    return;
8558e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu  }
86c3120769b3b5b3d86fd7bf83fbff8fb60369c213Ted Kremenek
87c3120769b3b5b3d86fd7bf83fbff8fb60369c213Ted Kremenek  // Array bound check succeeded.  From this point forward the array bound
88c3120769b3b5b3d86fd7bf83fbff8fb60369c213Ted Kremenek  // should always succeed.
890bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks  C.addTransition(StInBound);
9058e689fead1490611bcd114fb707bfc08a12049eZhongxing Xu}
918be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidis
928be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidisvoid ento::registerArrayBoundChecker(CheckerManager &mgr) {
938be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidis  mgr.registerChecker<ArrayBoundChecker>();
948be5b3aced37e1c7728741c60d47011f11649a58Argyrios Kyrtzidis}
95