141 lines · cpp
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-exception6//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 InvalidatedIteratorChecker29 : 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} // namespace51 52void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,53 CheckerContext &C) const {54 // Check for access of invalidated position55 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 positions62 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();76 UnaryOperatorKind OK = UO->getOpcode();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();87 BinaryOperatorKind OK = BO->getOpcode();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,126 CheckerContext &C,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}141