brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · 2e21f61 Raw
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