InvalidatedIteratorChecker.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  13. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  14. #include "clang/StaticAnalyzer/Core/Checker.h"
  15. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  16. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  17. #include "Iterator.h"
  18. using namespace clang;
  19. using namespace ento;
  20. using namespace iterator;
  21. namespace {
  22. class InvalidatedIteratorChecker
  23. : public Checker<check::PreCall, check::PreStmt<UnaryOperator>,
  24. check::PreStmt<BinaryOperator>,
  25. check::PreStmt<ArraySubscriptExpr>,
  26. check::PreStmt<MemberExpr>> {
  27. std::unique_ptr<BugType> InvalidatedBugType;
  28. void verifyAccess(CheckerContext &C, const SVal &Val) const;
  29. void reportBug(const StringRef &Message, const SVal &Val,
  30. CheckerContext &C, ExplodedNode *ErrNode) const;
  31. public:
  32. InvalidatedIteratorChecker();
  33. void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
  34. void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
  35. void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
  36. void checkPreStmt(const ArraySubscriptExpr *ASE, CheckerContext &C) const;
  37. void checkPreStmt(const MemberExpr *ME, CheckerContext &C) const;
  38. };
  39. } //namespace
  40. InvalidatedIteratorChecker::InvalidatedIteratorChecker() {
  41. InvalidatedBugType.reset(
  42. new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
  43. }
  44. void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,
  45. CheckerContext &C) const {
  46. // Check for access of invalidated position
  47. const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  48. if (!Func)
  49. return;
  50. if (Func->isOverloadedOperator() &&
  51. isAccessOperator(Func->getOverloadedOperator())) {
  52. // Check for any kind of access of invalidated iterator positions
  53. if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
  54. verifyAccess(C, InstCall->getCXXThisVal());
  55. } else {
  56. verifyAccess(C, Call.getArgSVal(0));
  57. }
  58. }
  59. }
  60. void InvalidatedIteratorChecker::checkPreStmt(const UnaryOperator *UO,
  61. CheckerContext &C) const {
  62. if (isa<CXXThisExpr>(UO->getSubExpr()))
  63. return;
  64. ProgramStateRef State = C.getState();
  65. UnaryOperatorKind OK = UO->getOpcode();
  66. SVal SubVal = State->getSVal(UO->getSubExpr(), C.getLocationContext());
  67. if (isAccessOperator(OK)) {
  68. verifyAccess(C, SubVal);
  69. }
  70. }
  71. void InvalidatedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
  72. CheckerContext &C) const {
  73. ProgramStateRef State = C.getState();
  74. BinaryOperatorKind OK = BO->getOpcode();
  75. SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext());
  76. if (isAccessOperator(OK)) {
  77. verifyAccess(C, LVal);
  78. }
  79. }
  80. void InvalidatedIteratorChecker::checkPreStmt(const ArraySubscriptExpr *ASE,
  81. CheckerContext &C) const {
  82. ProgramStateRef State = C.getState();
  83. SVal LVal = State->getSVal(ASE->getLHS(), C.getLocationContext());
  84. verifyAccess(C, LVal);
  85. }
  86. void InvalidatedIteratorChecker::checkPreStmt(const MemberExpr *ME,
  87. CheckerContext &C) const {
  88. if (!ME->isArrow() || ME->isImplicitAccess())
  89. return;
  90. ProgramStateRef State = C.getState();
  91. SVal BaseVal = State->getSVal(ME->getBase(), C.getLocationContext());
  92. verifyAccess(C, BaseVal);
  93. }
  94. void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
  95. auto State = C.getState();
  96. const auto *Pos = getIteratorPosition(State, Val);
  97. if (Pos && !Pos->isValid()) {
  98. auto *N = C.generateErrorNode(State);
  99. if (!N) {
  100. return;
  101. }
  102. reportBug("Invalidated iterator accessed.", Val, C, N);
  103. }
  104. }
  105. void InvalidatedIteratorChecker::reportBug(const StringRef &Message,
  106. const SVal &Val, CheckerContext &C,
  107. ExplodedNode *ErrNode) const {
  108. auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
  109. Message, ErrNode);
  110. R->markInteresting(Val);
  111. C.emitReport(std::move(R));
  112. }
  113. void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) {
  114. mgr.registerChecker<InvalidatedIteratorChecker>();
  115. }
  116. bool ento::shouldRegisterInvalidatedIteratorChecker(const CheckerManager &mgr) {
  117. return true;
  118. }