xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp (revision 96ec447a6ae39edff92674e9849de2bf21bfd430)
1afb13afcSAdam Balogh //===-- InvalidatedIteratorChecker.cpp ----------------------------*- C++ -*--//
2afb13afcSAdam Balogh //
3afb13afcSAdam Balogh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4afb13afcSAdam Balogh // See https://llvm.org/LICENSE.txt for license information.
5afb13afcSAdam Balogh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6afb13afcSAdam Balogh //
7afb13afcSAdam Balogh //===----------------------------------------------------------------------===//
8afb13afcSAdam Balogh //
9afb13afcSAdam Balogh // Defines a checker for access of invalidated iterators.
10afb13afcSAdam Balogh //
11afb13afcSAdam Balogh //===----------------------------------------------------------------------===//
12afb13afcSAdam Balogh 
13afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
15afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/Checker.h"
16afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17afb13afcSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18afb13afcSAdam Balogh 
19afb13afcSAdam Balogh 
20afb13afcSAdam Balogh #include "Iterator.h"
21afb13afcSAdam Balogh 
22afb13afcSAdam Balogh using namespace clang;
23afb13afcSAdam Balogh using namespace ento;
24afb13afcSAdam Balogh using namespace iterator;
25afb13afcSAdam Balogh 
26afb13afcSAdam Balogh namespace {
27afb13afcSAdam Balogh 
28afb13afcSAdam Balogh class InvalidatedIteratorChecker
299e63b190SAdam Balogh   : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
309e63b190SAdam Balogh                    check::PreStmt<BinaryOperator>,
319e63b190SAdam Balogh                    check::PreStmt<ArraySubscriptExpr>,
329e63b190SAdam Balogh                    check::PreStmt<MemberExpr>> {
33afb13afcSAdam Balogh 
3418f219c5SBalazs Benics   const BugType InvalidatedBugType{this, "Iterator invalidated",
3518f219c5SBalazs Benics                                    "Misuse of STL APIs"};
36afb13afcSAdam Balogh 
37*8ee3dfd7SBalazs Benics   void verifyAccess(CheckerContext &C, SVal Val) const;
3818f219c5SBalazs Benics   void reportBug(StringRef Message, SVal Val, CheckerContext &C,
3918f219c5SBalazs Benics                  ExplodedNode *ErrNode) const;
40afb13afcSAdam Balogh 
4118f219c5SBalazs Benics public:
42afb13afcSAdam Balogh   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
439e63b190SAdam Balogh   void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
449e63b190SAdam Balogh   void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
459e63b190SAdam Balogh   void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
469e63b190SAdam Balogh   void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
47afb13afcSAdam Balogh 
48afb13afcSAdam Balogh };
49afb13afcSAdam Balogh 
50afb13afcSAdam Balogh } // namespace
51afb13afcSAdam Balogh 
checkPreCall(const CallEvent & Call,CheckerContext & C) const52afb13afcSAdam Balogh void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,
53afb13afcSAdam Balogh                                               CheckerContext &C) const {
54afb13afcSAdam Balogh   // Check for access of invalidated position
55afb13afcSAdam Balogh   const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
56afb13afcSAdam Balogh   if (!Func)
57afb13afcSAdam Balogh     return;
58afb13afcSAdam Balogh 
59afb13afcSAdam Balogh   if (Func->isOverloadedOperator() &&
60afb13afcSAdam Balogh       isAccessOperator(Func->getOverloadedOperator())) {
61afb13afcSAdam Balogh     // Check for any kind of access of invalidated iterator positions
62afb13afcSAdam Balogh     if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
63afb13afcSAdam Balogh       verifyAccess(C, InstCall->getCXXThisVal());
64afb13afcSAdam Balogh     } else {
65afb13afcSAdam Balogh       verifyAccess(C, Call.getArgSVal(0));
66afb13afcSAdam Balogh     }
67afb13afcSAdam Balogh   }
68afb13afcSAdam Balogh }
69afb13afcSAdam Balogh 
checkPreStmt(const UnaryOperator * UO,CheckerContext & C) const709e63b190SAdam Balogh void InvalidatedIteratorChecker::checkPreStmt(const UnaryOperator *UO,
719e63b190SAdam Balogh                                               CheckerContext &C) const {
729e63b190SAdam Balogh   if (isa<CXXThisExpr>(UO->getSubExpr()))
739e63b190SAdam Balogh     return;
749e63b190SAdam Balogh 
759e63b190SAdam Balogh   ProgramStateRef State = C.getState();
769e63b190SAdam Balogh   UnaryOperatorKind OK = UO->getOpcode();
779e63b190SAdam Balogh   SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
789e63b190SAdam Balogh 
799e63b190SAdam Balogh   if (isAccessOperator(OK)) {
809e63b190SAdam Balogh     verifyAccess(C, SubVal);
819e63b190SAdam Balogh   }
829e63b190SAdam Balogh }
839e63b190SAdam Balogh 
checkPreStmt(const BinaryOperator * BO,CheckerContext & C) const849e63b190SAdam Balogh void InvalidatedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
859e63b190SAdam Balogh                                               CheckerContext &C) const {
869e63b190SAdam Balogh   ProgramStateRef State = C.getState();
879e63b190SAdam Balogh   BinaryOperatorKind OK = BO->getOpcode();
889e63b190SAdam Balogh   SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
899e63b190SAdam Balogh 
909e63b190SAdam Balogh   if (isAccessOperator(OK)) {
919e63b190SAdam Balogh     verifyAccess(C, LVal);
929e63b190SAdam Balogh   }
939e63b190SAdam Balogh }
949e63b190SAdam Balogh 
checkPreStmt(const ArraySubscriptExpr * ASE,CheckerContext & C) const959e63b190SAdam Balogh void InvalidatedIteratorChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
969e63b190SAdam Balogh                                               CheckerContext &C) const {
979e63b190SAdam Balogh   ProgramStateRef State = C.getState();
989e63b190SAdam Balogh   SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
999e63b190SAdam Balogh   verifyAccess(C, LVal);
1009e63b190SAdam Balogh }
1019e63b190SAdam Balogh 
checkPreStmt(const MemberExpr * ME,CheckerContext & C) const1029e63b190SAdam Balogh void InvalidatedIteratorChecker::checkPreStmt(const MemberExpr *ME,
1039e63b190SAdam Balogh                                               CheckerContext &C) const {
1049e63b190SAdam Balogh   if (!ME->isArrow() || ME->isImplicitAccess())
1059e63b190SAdam Balogh     return;
1069e63b190SAdam Balogh 
1079e63b190SAdam Balogh   ProgramStateRef State = C.getState();
1089e63b190SAdam Balogh   SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
1099e63b190SAdam Balogh   verifyAccess(C, BaseVal);
1109e63b190SAdam Balogh }
1119e63b190SAdam Balogh 
verifyAccess(CheckerContext & C,SVal Val) const112*8ee3dfd7SBalazs Benics void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C,
113*8ee3dfd7SBalazs Benics                                               SVal Val) const {
114afb13afcSAdam Balogh   auto State = C.getState();
115afb13afcSAdam Balogh   const auto *Pos = getIteratorPosition(State, Val);
116afb13afcSAdam Balogh   if (Pos && !Pos->isValid()) {
117afb13afcSAdam Balogh     auto *N = C.generateErrorNode(State);
118afb13afcSAdam Balogh     if (!N) {
119afb13afcSAdam Balogh       return;
120afb13afcSAdam Balogh     }
121afb13afcSAdam Balogh     reportBug("Invalidated iterator accessed.", Val, C, N);
122afb13afcSAdam Balogh   }
123afb13afcSAdam Balogh }
124afb13afcSAdam Balogh 
reportBug(StringRef Message,SVal Val,CheckerContext & C,ExplodedNode * ErrNode) const12518f219c5SBalazs Benics void InvalidatedIteratorChecker::reportBug(StringRef Message, SVal Val,
12618f219c5SBalazs Benics                                            CheckerContext &C,
127afb13afcSAdam Balogh                                            ExplodedNode *ErrNode) const {
12818f219c5SBalazs Benics   auto R = std::make_unique<PathSensitiveBugReport>(InvalidatedBugType, Message,
12918f219c5SBalazs Benics                                                     ErrNode);
130afb13afcSAdam Balogh   R->markInteresting(Val);
131afb13afcSAdam Balogh   C.emitReport(std::move(R));
132afb13afcSAdam Balogh }
133afb13afcSAdam Balogh 
registerInvalidatedIteratorChecker(CheckerManager & mgr)134afb13afcSAdam Balogh void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) {
135afb13afcSAdam Balogh   mgr.registerChecker<InvalidatedIteratorChecker>();
136afb13afcSAdam Balogh }
137afb13afcSAdam Balogh 
shouldRegisterInvalidatedIteratorChecker(const CheckerManager & mgr)138bda3dd0dSKirstóf Umann bool ento::shouldRegisterInvalidatedIteratorChecker(const CheckerManager &mgr) {
139afb13afcSAdam Balogh   return true;
140afb13afcSAdam Balogh }
141