CXXSelfAssignmentChecker.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. //=== CXXSelfAssignmentChecker.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. // This file defines CXXSelfAssignmentChecker, which tests all custom defined
  10. // copy and move assignment operators for the case of self assignment, thus
  11. // where the parameter refers to the same location where the this pointer
  12. // points to. The checker itself does not do any checks at all, but it
  13. // causes the analyzer to check every copy and move assignment operator twice:
  14. // once for when 'this' aliases with the parameter and once for when it may not.
  15. // It is the task of the other enabled checkers to find the bugs in these two
  16. // different cases.
  17. //
  18. //===----------------------------------------------------------------------===//
  19. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  20. #include "clang/StaticAnalyzer/Core/Checker.h"
  21. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  22. using namespace clang;
  23. using namespace ento;
  24. namespace {
  25. class CXXSelfAssignmentChecker : public Checker<check::BeginFunction> {
  26. public:
  27. CXXSelfAssignmentChecker();
  28. void checkBeginFunction(CheckerContext &C) const;
  29. };
  30. }
  31. CXXSelfAssignmentChecker::CXXSelfAssignmentChecker() {}
  32. void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
  33. if (!C.inTopFrame())
  34. return;
  35. const auto *LCtx = C.getLocationContext();
  36. const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
  37. if (!MD)
  38. return;
  39. if (!MD->isCopyAssignmentOperator() && !MD->isMoveAssignmentOperator())
  40. return;
  41. auto &State = C.getState();
  42. auto &SVB = C.getSValBuilder();
  43. auto ThisVal =
  44. State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
  45. auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx));
  46. auto ParamVal = State->getSVal(Param);
  47. ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx);
  48. const NoteTag *SelfAssignTag =
  49. C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
  50. SmallString<256> Msg;
  51. llvm::raw_svector_ostream Out(Msg);
  52. Out << "Assuming " << MD->getParamDecl(0)->getName() << " == *this";
  53. return std::string(Out.str());
  54. });
  55. C.addTransition(SelfAssignState, SelfAssignTag);
  56. ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx);
  57. const NoteTag *NonSelfAssignTag =
  58. C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
  59. SmallString<256> Msg;
  60. llvm::raw_svector_ostream Out(Msg);
  61. Out << "Assuming " << MD->getParamDecl(0)->getName() << " != *this";
  62. return std::string(Out.str());
  63. });
  64. C.addTransition(NonSelfAssignState, NonSelfAssignTag);
  65. }
  66. void ento::registerCXXSelfAssignmentChecker(CheckerManager &Mgr) {
  67. Mgr.registerChecker<CXXSelfAssignmentChecker>();
  68. }
  69. bool ento::shouldRegisterCXXSelfAssignmentChecker(const CheckerManager &mgr) {
  70. return true;
  71. }