Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp
Line
Count
Source (jump to first uncovered line)
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
22
using namespace clang;
23
using namespace ento;
24
using namespace iterator;
25
26
namespace {
27
28
class InvalidatedIteratorChecker
29
  : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
30
                   check::PreStmt<BinaryOperator>,
31
                   check::PreStmt<ArraySubscriptExpr>,
32
                   check::PreStmt<MemberExpr>> {
33
34
  std::unique_ptr<BugType> InvalidatedBugType;
35
36
  void verifyAccess(CheckerContext &C, const SVal &Val) const;
37
  void reportBug(const StringRef &Message, const SVal &Val,
38
                 CheckerContext &C, ExplodedNode *ErrNode) const;
39
public:
40
  InvalidatedIteratorChecker();
41
42
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
43
  void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
44
  void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
45
  void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
46
  void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
47
48
};
49
50
} //namespace
51
52
2
InvalidatedIteratorChecker::InvalidatedIteratorChecker() {
53
2
  InvalidatedBugType.reset(
54
2
      new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
55
2
}
56
57
void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,
58
217
                                              CheckerContext &C) const {
59
  // Check for access of invalidated position
60
217
  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
61
217
  if (!Func)
62
0
    return;
63
64
217
  if (Func->isOverloadedOperator() &&
65
217
      
isAccessOperator(Func->getOverloadedOperator())48
) {
66
    // Check for any kind of access of invalidated iterator positions
67
48
    if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
68
48
      verifyAccess(C, InstCall->getCXXThisVal());
69
48
    } else {
70
0
      verifyAccess(C, Call.getArgSVal(0));
71
0
    }
72
48
  }
73
217
}
74
75
void InvalidatedIteratorChecker::checkPreStmt(const UnaryOperator *UO,
76
28
                                              CheckerContext &C) const {
77
28
  if (isa<CXXThisExpr>(UO->getSubExpr()))
78
8
    return;
79
80
20
  ProgramStateRef State = C.getState();
81
20
  UnaryOperatorKind OK = UO->getOpcode();
82
20
  SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
83
84
20
  if (isAccessOperator(OK)) {
85
20
    verifyAccess(C, SubVal);
86
20
  }
87
20
}
88
89
void InvalidatedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
90
17
                                              CheckerContext &C) const {
91
17
  ProgramStateRef State = C.getState();
92
17
  BinaryOperatorKind OK = BO->getOpcode();
93
17
  SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
94
95
17
  if (isAccessOperator(OK)) {
96
17
    verifyAccess(C, LVal);
97
17
  }
98
17
}
99
100
void InvalidatedIteratorChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
101
2
                                              CheckerContext &C) const {
102
2
  ProgramStateRef State = C.getState();
103
2
  SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
104
2
  verifyAccess(C, LVal);
105
2
}
106
107
void InvalidatedIteratorChecker::checkPreStmt(const MemberExpr *ME,
108
142
                                              CheckerContext &C) const {
109
142
  if (!ME->isArrow() || 
ME->isImplicitAccess()36
)
110
142
    return;
111
112
0
  ProgramStateRef State = C.getState();
113
0
  SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
114
0
  verifyAccess(C, BaseVal);
115
0
}
116
117
87
void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
118
87
  auto State = C.getState();
119
87
  const auto *Pos = getIteratorPosition(State, Val);
120
87
  if (Pos && 
!Pos->isValid()72
) {
121
40
    auto *N = C.generateErrorNode(State);
122
40
    if (!N) {
123
0
      return;
124
0
    }
125
40
    reportBug("Invalidated iterator accessed.", Val, C, N);
126
40
  }
127
87
}
128
129
void InvalidatedIteratorChecker::reportBug(const StringRef &Message,
130
                                           const SVal &Val, CheckerContext &C,
131
40
                                           ExplodedNode *ErrNode) const {
132
40
  auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
133
40
                                                    Message, ErrNode);
134
40
  R->markInteresting(Val);
135
40
  C.emitReport(std::move(R));
136
40
}
137
138
2
void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) {
139
2
  mgr.registerChecker<InvalidatedIteratorChecker>();
140
2
}
141
142
4
bool ento::shouldRegisterInvalidatedIteratorChecker(const CheckerManager &mgr) {
143
4
  return true;
144
4
}