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