SmartPtrChecker.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // SmartPtrChecker.cpp - Check for smart pointer dereference - 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 a checker that check for null dereference of C++ smart
  10. // pointer.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "SmartPtr.h"
  14. #include "clang/AST/DeclCXX.h"
  15. #include "clang/AST/ExprCXX.h"
  16. #include "clang/AST/Type.h"
  17. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  18. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  19. #include "clang/StaticAnalyzer/Core/Checker.h"
  20. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  21. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  22. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  23. #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
  25. #include "llvm/ADT/StringRef.h"
  26. using namespace clang;
  27. using namespace ento;
  28. namespace {
  29. static const BugType *NullDereferenceBugTypePtr;
  30. class SmartPtrChecker : public Checker<check::PreCall> {
  31. public:
  32. void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
  33. BugType NullDereferenceBugType{this, "Null SmartPtr dereference",
  34. "C++ Smart Pointer"};
  35. private:
  36. void reportBug(CheckerContext &C, const MemRegion *DerefRegion,
  37. const CallEvent &Call) const;
  38. void explainDereference(llvm::raw_ostream &OS, const MemRegion *DerefRegion,
  39. const CallEvent &Call) const;
  40. };
  41. } // end of anonymous namespace
  42. // Define the inter-checker API.
  43. namespace clang {
  44. namespace ento {
  45. namespace smartptr {
  46. const BugType *getNullDereferenceBugType() { return NullDereferenceBugTypePtr; }
  47. } // namespace smartptr
  48. } // namespace ento
  49. } // namespace clang
  50. void SmartPtrChecker::checkPreCall(const CallEvent &Call,
  51. CheckerContext &C) const {
  52. if (!smartptr::isStdSmartPtrCall(Call))
  53. return;
  54. ProgramStateRef State = C.getState();
  55. const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
  56. if (!OC)
  57. return;
  58. const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
  59. if (!ThisRegion)
  60. return;
  61. OverloadedOperatorKind OOK = OC->getOverloadedOperator();
  62. if (OOK == OO_Star || OOK == OO_Arrow) {
  63. if (smartptr::isNullSmartPtr(State, ThisRegion))
  64. reportBug(C, ThisRegion, Call);
  65. }
  66. }
  67. void SmartPtrChecker::reportBug(CheckerContext &C, const MemRegion *DerefRegion,
  68. const CallEvent &Call) const {
  69. ExplodedNode *ErrNode = C.generateErrorNode();
  70. if (!ErrNode)
  71. return;
  72. llvm::SmallString<128> Str;
  73. llvm::raw_svector_ostream OS(Str);
  74. explainDereference(OS, DerefRegion, Call);
  75. auto R = std::make_unique<PathSensitiveBugReport>(NullDereferenceBugType,
  76. OS.str(), ErrNode);
  77. R->markInteresting(DerefRegion);
  78. C.emitReport(std::move(R));
  79. }
  80. void SmartPtrChecker::explainDereference(llvm::raw_ostream &OS,
  81. const MemRegion *DerefRegion,
  82. const CallEvent &Call) const {
  83. OS << "Dereference of null smart pointer ";
  84. DerefRegion->printPretty(OS);
  85. }
  86. void ento::registerSmartPtrChecker(CheckerManager &Mgr) {
  87. SmartPtrChecker *Checker = Mgr.registerChecker<SmartPtrChecker>();
  88. NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
  89. }
  90. bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {
  91. const LangOptions &LO = mgr.getLangOpts();
  92. return LO.CPlusPlus;
  93. }