xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp (revision 06d100a69a08632e6a553a7fb4d3750b55145946)
120e271a9SNithin Vadukkumchery Rajendrakumar // SmartPtrChecker.cpp - Check for smart pointer dereference - C++ --------===//
220e271a9SNithin Vadukkumchery Rajendrakumar //
320e271a9SNithin Vadukkumchery Rajendrakumar // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
420e271a9SNithin Vadukkumchery Rajendrakumar // See https://llvm.org/LICENSE.txt for license information.
520e271a9SNithin Vadukkumchery Rajendrakumar // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
620e271a9SNithin Vadukkumchery Rajendrakumar //
720e271a9SNithin Vadukkumchery Rajendrakumar //===----------------------------------------------------------------------===//
820e271a9SNithin Vadukkumchery Rajendrakumar //
920e271a9SNithin Vadukkumchery Rajendrakumar // This file defines a checker that check for null dereference of C++ smart
1020e271a9SNithin Vadukkumchery Rajendrakumar // pointer.
1120e271a9SNithin Vadukkumchery Rajendrakumar //
1220e271a9SNithin Vadukkumchery Rajendrakumar //===----------------------------------------------------------------------===//
1320e271a9SNithin Vadukkumchery Rajendrakumar #include "SmartPtr.h"
1420e271a9SNithin Vadukkumchery Rajendrakumar 
1520e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/DeclCXX.h"
1620e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/ExprCXX.h"
1720e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/Type.h"
1820e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
1920e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
2020e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/Checker.h"
2120e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/CheckerManager.h"
2220e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
2320e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2420e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
2520e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
26*06d100a6SNithin Vadukkumchery Rajendrakumar #include "llvm/ADT/StringRef.h"
2720e271a9SNithin Vadukkumchery Rajendrakumar 
2820e271a9SNithin Vadukkumchery Rajendrakumar using namespace clang;
2920e271a9SNithin Vadukkumchery Rajendrakumar using namespace ento;
3020e271a9SNithin Vadukkumchery Rajendrakumar 
3120e271a9SNithin Vadukkumchery Rajendrakumar namespace {
32*06d100a6SNithin Vadukkumchery Rajendrakumar 
33*06d100a6SNithin Vadukkumchery Rajendrakumar static const BugType *NullDereferenceBugTypePtr;
34*06d100a6SNithin Vadukkumchery Rajendrakumar 
3520e271a9SNithin Vadukkumchery Rajendrakumar class SmartPtrChecker : public Checker<check::PreCall> {
36*06d100a6SNithin Vadukkumchery Rajendrakumar public:
37*06d100a6SNithin Vadukkumchery Rajendrakumar   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
3820e271a9SNithin Vadukkumchery Rajendrakumar   BugType NullDereferenceBugType{this, "Null SmartPtr dereference",
3920e271a9SNithin Vadukkumchery Rajendrakumar                                  "C++ Smart Pointer"};
4020e271a9SNithin Vadukkumchery Rajendrakumar 
4120e271a9SNithin Vadukkumchery Rajendrakumar private:
42*06d100a6SNithin Vadukkumchery Rajendrakumar   void reportBug(CheckerContext &C, const MemRegion *DerefRegion,
43*06d100a6SNithin Vadukkumchery Rajendrakumar                  const CallEvent &Call) const;
44*06d100a6SNithin Vadukkumchery Rajendrakumar   void explainDereference(llvm::raw_ostream &OS, const MemRegion *DerefRegion,
45*06d100a6SNithin Vadukkumchery Rajendrakumar                           const CallEvent &Call) const;
4620e271a9SNithin Vadukkumchery Rajendrakumar };
4720e271a9SNithin Vadukkumchery Rajendrakumar } // end of anonymous namespace
4820e271a9SNithin Vadukkumchery Rajendrakumar 
49*06d100a6SNithin Vadukkumchery Rajendrakumar // Define the inter-checker API.
50*06d100a6SNithin Vadukkumchery Rajendrakumar namespace clang {
51*06d100a6SNithin Vadukkumchery Rajendrakumar namespace ento {
52*06d100a6SNithin Vadukkumchery Rajendrakumar namespace smartptr {
53*06d100a6SNithin Vadukkumchery Rajendrakumar 
getNullDereferenceBugType()54*06d100a6SNithin Vadukkumchery Rajendrakumar const BugType *getNullDereferenceBugType() { return NullDereferenceBugTypePtr; }
55*06d100a6SNithin Vadukkumchery Rajendrakumar 
56*06d100a6SNithin Vadukkumchery Rajendrakumar } // namespace smartptr
57*06d100a6SNithin Vadukkumchery Rajendrakumar } // namespace ento
58*06d100a6SNithin Vadukkumchery Rajendrakumar } // namespace clang
59*06d100a6SNithin Vadukkumchery Rajendrakumar 
checkPreCall(const CallEvent & Call,CheckerContext & C) const6020e271a9SNithin Vadukkumchery Rajendrakumar void SmartPtrChecker::checkPreCall(const CallEvent &Call,
6120e271a9SNithin Vadukkumchery Rajendrakumar                                    CheckerContext &C) const {
6220e271a9SNithin Vadukkumchery Rajendrakumar   if (!smartptr::isStdSmartPtrCall(Call))
6320e271a9SNithin Vadukkumchery Rajendrakumar     return;
6420e271a9SNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
6520e271a9SNithin Vadukkumchery Rajendrakumar   const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
6620e271a9SNithin Vadukkumchery Rajendrakumar   if (!OC)
6720e271a9SNithin Vadukkumchery Rajendrakumar     return;
6820e271a9SNithin Vadukkumchery Rajendrakumar   const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
6920e271a9SNithin Vadukkumchery Rajendrakumar   if (!ThisRegion)
7020e271a9SNithin Vadukkumchery Rajendrakumar     return;
7120e271a9SNithin Vadukkumchery Rajendrakumar 
7220e271a9SNithin Vadukkumchery Rajendrakumar   OverloadedOperatorKind OOK = OC->getOverloadedOperator();
7320e271a9SNithin Vadukkumchery Rajendrakumar   if (OOK == OO_Star || OOK == OO_Arrow) {
7420e271a9SNithin Vadukkumchery Rajendrakumar     if (smartptr::isNullSmartPtr(State, ThisRegion))
75*06d100a6SNithin Vadukkumchery Rajendrakumar       reportBug(C, ThisRegion, Call);
7620e271a9SNithin Vadukkumchery Rajendrakumar   }
7720e271a9SNithin Vadukkumchery Rajendrakumar }
7820e271a9SNithin Vadukkumchery Rajendrakumar 
reportBug(CheckerContext & C,const MemRegion * DerefRegion,const CallEvent & Call) const79*06d100a6SNithin Vadukkumchery Rajendrakumar void SmartPtrChecker::reportBug(CheckerContext &C, const MemRegion *DerefRegion,
8020e271a9SNithin Vadukkumchery Rajendrakumar                                 const CallEvent &Call) const {
8120e271a9SNithin Vadukkumchery Rajendrakumar   ExplodedNode *ErrNode = C.generateErrorNode();
8220e271a9SNithin Vadukkumchery Rajendrakumar   if (!ErrNode)
8320e271a9SNithin Vadukkumchery Rajendrakumar     return;
84*06d100a6SNithin Vadukkumchery Rajendrakumar   llvm::SmallString<128> Str;
85*06d100a6SNithin Vadukkumchery Rajendrakumar   llvm::raw_svector_ostream OS(Str);
86*06d100a6SNithin Vadukkumchery Rajendrakumar   explainDereference(OS, DerefRegion, Call);
87*06d100a6SNithin Vadukkumchery Rajendrakumar   auto R = std::make_unique<PathSensitiveBugReport>(NullDereferenceBugType,
88*06d100a6SNithin Vadukkumchery Rajendrakumar                                                     OS.str(), ErrNode);
89*06d100a6SNithin Vadukkumchery Rajendrakumar   R->markInteresting(DerefRegion);
9020e271a9SNithin Vadukkumchery Rajendrakumar   C.emitReport(std::move(R));
9120e271a9SNithin Vadukkumchery Rajendrakumar }
9220e271a9SNithin Vadukkumchery Rajendrakumar 
explainDereference(llvm::raw_ostream & OS,const MemRegion * DerefRegion,const CallEvent & Call) const93*06d100a6SNithin Vadukkumchery Rajendrakumar void SmartPtrChecker::explainDereference(llvm::raw_ostream &OS,
94*06d100a6SNithin Vadukkumchery Rajendrakumar                                          const MemRegion *DerefRegion,
95*06d100a6SNithin Vadukkumchery Rajendrakumar                                          const CallEvent &Call) const {
96*06d100a6SNithin Vadukkumchery Rajendrakumar   OS << "Dereference of null smart pointer ";
97*06d100a6SNithin Vadukkumchery Rajendrakumar   DerefRegion->printPretty(OS);
98*06d100a6SNithin Vadukkumchery Rajendrakumar }
99*06d100a6SNithin Vadukkumchery Rajendrakumar 
registerSmartPtrChecker(CheckerManager & Mgr)10020e271a9SNithin Vadukkumchery Rajendrakumar void ento::registerSmartPtrChecker(CheckerManager &Mgr) {
101*06d100a6SNithin Vadukkumchery Rajendrakumar   SmartPtrChecker *Checker = Mgr.registerChecker<SmartPtrChecker>();
102*06d100a6SNithin Vadukkumchery Rajendrakumar   NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
10320e271a9SNithin Vadukkumchery Rajendrakumar }
10420e271a9SNithin Vadukkumchery Rajendrakumar 
shouldRegisterSmartPtrChecker(const CheckerManager & mgr)10520e271a9SNithin Vadukkumchery Rajendrakumar bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {
10620e271a9SNithin Vadukkumchery Rajendrakumar   const LangOptions &LO = mgr.getLangOpts();
10720e271a9SNithin Vadukkumchery Rajendrakumar   return LO.CPlusPlus;
10820e271a9SNithin Vadukkumchery Rajendrakumar }
109