InvalidatedIteratorChecker.cpp revision 360784
1//===-- InvalidatedIteratorChecker.cpp ----------------------------*- C++ -*--//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Defines a checker for access of invalidated iterators.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
15#include "clang/StaticAnalyzer/Core/Checker.h"
16#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18
19
20#include "Iterator.h"
21
22using namespace clang;
23using namespace ento;
24using namespace iterator;
25
26namespace {
27
28class InvalidatedIteratorChecker
29  : public Checker<check::PreCall> {
30
31  std::unique_ptr<BugType> InvalidatedBugType;
32
33  void verifyAccess(CheckerContext &C, const SVal &Val) const;
34  void reportBug(const StringRef &Message, const SVal &Val,
35                 CheckerContext &C, ExplodedNode *ErrNode) const;
36public:
37  InvalidatedIteratorChecker();
38
39  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
40
41};
42
43} //namespace
44
45InvalidatedIteratorChecker::InvalidatedIteratorChecker() {
46  InvalidatedBugType.reset(
47      new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
48}
49
50void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,
51                                              CheckerContext &C) const {
52  // Check for access of invalidated position
53  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
54  if (!Func)
55    return;
56
57  if (Func->isOverloadedOperator() &&
58      isAccessOperator(Func->getOverloadedOperator())) {
59    // Check for any kind of access of invalidated iterator positions
60    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
61      verifyAccess(C, InstCall->getCXXThisVal());
62    } else {
63      verifyAccess(C, Call.getArgSVal(0));
64    }
65  }
66}
67
68void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
69  auto State = C.getState();
70  const auto *Pos = getIteratorPosition(State, Val);
71  if (Pos && !Pos->isValid()) {
72    auto *N = C.generateErrorNode(State);
73    if (!N) {
74      return;
75    }
76    reportBug("Invalidated iterator accessed.", Val, C, N);
77  }
78}
79
80void InvalidatedIteratorChecker::reportBug(const StringRef &Message,
81                                           const SVal &Val, CheckerContext &C,
82                                           ExplodedNode *ErrNode) const {
83  auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
84                                                    Message, ErrNode);
85  R->markInteresting(Val);
86  C.emitReport(std::move(R));
87}
88
89void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) {
90  mgr.registerChecker<InvalidatedIteratorChecker>();
91}
92
93bool ento::shouldRegisterInvalidatedIteratorChecker(const LangOptions &LO) {
94  return true;
95}
96