clang 20.0.0git
InvalidatedIteratorChecker.cpp
Go to the documentation of this file.
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
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, check::PreStmt<UnaryOperator>,
30 check::PreStmt<BinaryOperator>,
31 check::PreStmt<ArraySubscriptExpr>,
32 check::PreStmt<MemberExpr>> {
33
34 const BugType InvalidatedBugType{this, "Iterator invalidated",
35 "Misuse of STL APIs"};
36
37 void verifyAccess(CheckerContext &C, SVal Val) const;
38 void reportBug(StringRef Message, SVal Val, CheckerContext &C,
39 ExplodedNode *ErrNode) const;
40
41public:
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
52void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,
53 CheckerContext &C) const {
54 // Check for access of invalidated position
55 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
56 if (!Func)
57 return;
58
59 if (Func->isOverloadedOperator() &&
60 isAccessOperator(Func->getOverloadedOperator())) {
61 // Check for any kind of access of invalidated iterator positions
62 if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
63 verifyAccess(C, InstCall->getCXXThisVal());
64 } else {
65 verifyAccess(C, Call.getArgSVal(0));
66 }
67 }
68}
69
70void InvalidatedIteratorChecker::checkPreStmt(const UnaryOperator *UO,
71 CheckerContext &C) const {
72 if (isa<CXXThisExpr>(UO->getSubExpr()))
73 return;
74
75 ProgramStateRef State = C.getState();
77 SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
78
79 if (isAccessOperator(OK)) {
80 verifyAccess(C, SubVal);
81 }
82}
83
84void InvalidatedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
85 CheckerContext &C) const {
86 ProgramStateRef State = C.getState();
88 SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
89
90 if (isAccessOperator(OK)) {
91 verifyAccess(C, LVal);
92 }
93}
94
95void InvalidatedIteratorChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
96 CheckerContext &C) const {
97 ProgramStateRef State = C.getState();
98 SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
99 verifyAccess(C, LVal);
100}
101
102void InvalidatedIteratorChecker::checkPreStmt(const MemberExpr *ME,
103 CheckerContext &C) const {
104 if (!ME->isArrow() || ME->isImplicitAccess())
105 return;
106
107 ProgramStateRef State = C.getState();
108 SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
109 verifyAccess(C, BaseVal);
110}
111
112void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C,
113 SVal Val) const {
114 auto State = C.getState();
115 const auto *Pos = getIteratorPosition(State, Val);
116 if (Pos && !Pos->isValid()) {
117 auto *N = C.generateErrorNode(State);
118 if (!N) {
119 return;
120 }
121 reportBug("Invalidated iterator accessed.", Val, C, N);
122 }
123}
124
125void InvalidatedIteratorChecker::reportBug(StringRef Message, SVal Val,
127 ExplodedNode *ErrNode) const {
128 auto R = std::make_unique<PathSensitiveBugReport>(InvalidatedBugType, Message,
129 ErrNode);
130 R->markInteresting(Val);
131 C.emitReport(std::move(R));
132}
133
134void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) {
135 mgr.registerChecker<InvalidatedIteratorChecker>();
136}
137
138bool ento::shouldRegisterInvalidatedIteratorChecker(const CheckerManager &mgr) {
139 return true;
140}
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition: Expr.h:2674
Expr * getLHS()
An array access can be written A[4] or 4[A] (both are equivalent).
Definition: Expr.h:2703
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3860
Expr * getLHS() const
Definition: Expr.h:3910
Opcode getOpcode() const
Definition: Expr.h:3905
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3187
bool isImplicitAccess() const
Determine whether the base of this explicit is implicit.
Definition: Expr.h:3385
Expr * getBase() const
Definition: Expr.h:3264
bool isArrow() const
Definition: Expr.h:3371
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition: Expr.h:2188
Expr * getSubExpr() const
Definition: Expr.h:2233
Opcode getOpcode() const
Definition: Expr.h:2228
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:153
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:55
const IteratorPosition * getIteratorPosition(ProgramStateRef State, SVal Val)
Definition: Iterator.cpp:184
bool isAccessOperator(OverloadedOperatorKind OK)
Definition: Iterator.cpp:126
The JSON file list parser is used to communicate input to InstallAPI.
BinaryOperatorKind
UnaryOperatorKind