xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
15ffd83dbSDimitry Andric // SmartPtrChecker.cpp - Check for smart pointer dereference - C++ --------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // This file defines a checker that check for null dereference of C++ smart
105ffd83dbSDimitry Andric // pointer.
115ffd83dbSDimitry Andric //
125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
135ffd83dbSDimitry Andric #include "SmartPtr.h"
145ffd83dbSDimitry Andric 
155ffd83dbSDimitry Andric #include "clang/AST/DeclCXX.h"
165ffd83dbSDimitry Andric #include "clang/AST/ExprCXX.h"
175ffd83dbSDimitry Andric #include "clang/AST/Type.h"
185ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
195ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
205ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
215ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
225ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
235ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
245ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
255ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
26*e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h"
275ffd83dbSDimitry Andric 
285ffd83dbSDimitry Andric using namespace clang;
295ffd83dbSDimitry Andric using namespace ento;
305ffd83dbSDimitry Andric 
315ffd83dbSDimitry Andric namespace {
32*e8d8bef9SDimitry Andric 
33*e8d8bef9SDimitry Andric static const BugType *NullDereferenceBugTypePtr;
34*e8d8bef9SDimitry Andric 
355ffd83dbSDimitry Andric class SmartPtrChecker : public Checker<check::PreCall> {
36*e8d8bef9SDimitry Andric public:
37*e8d8bef9SDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
385ffd83dbSDimitry Andric   BugType NullDereferenceBugType{this, "Null SmartPtr dereference",
395ffd83dbSDimitry Andric                                  "C++ Smart Pointer"};
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric private:
42*e8d8bef9SDimitry Andric   void reportBug(CheckerContext &C, const MemRegion *DerefRegion,
43*e8d8bef9SDimitry Andric                  const CallEvent &Call) const;
44*e8d8bef9SDimitry Andric   void explainDereference(llvm::raw_ostream &OS, const MemRegion *DerefRegion,
45*e8d8bef9SDimitry Andric                           const CallEvent &Call) const;
465ffd83dbSDimitry Andric };
475ffd83dbSDimitry Andric } // end of anonymous namespace
485ffd83dbSDimitry Andric 
49*e8d8bef9SDimitry Andric // Define the inter-checker API.
50*e8d8bef9SDimitry Andric namespace clang {
51*e8d8bef9SDimitry Andric namespace ento {
52*e8d8bef9SDimitry Andric namespace smartptr {
53*e8d8bef9SDimitry Andric 
getNullDereferenceBugType()54*e8d8bef9SDimitry Andric const BugType *getNullDereferenceBugType() { return NullDereferenceBugTypePtr; }
55*e8d8bef9SDimitry Andric 
56*e8d8bef9SDimitry Andric } // namespace smartptr
57*e8d8bef9SDimitry Andric } // namespace ento
58*e8d8bef9SDimitry Andric } // namespace clang
59*e8d8bef9SDimitry Andric 
checkPreCall(const CallEvent & Call,CheckerContext & C) const605ffd83dbSDimitry Andric void SmartPtrChecker::checkPreCall(const CallEvent &Call,
615ffd83dbSDimitry Andric                                    CheckerContext &C) const {
625ffd83dbSDimitry Andric   if (!smartptr::isStdSmartPtrCall(Call))
635ffd83dbSDimitry Andric     return;
645ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
655ffd83dbSDimitry Andric   const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
665ffd83dbSDimitry Andric   if (!OC)
675ffd83dbSDimitry Andric     return;
685ffd83dbSDimitry Andric   const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
695ffd83dbSDimitry Andric   if (!ThisRegion)
705ffd83dbSDimitry Andric     return;
715ffd83dbSDimitry Andric 
725ffd83dbSDimitry Andric   OverloadedOperatorKind OOK = OC->getOverloadedOperator();
735ffd83dbSDimitry Andric   if (OOK == OO_Star || OOK == OO_Arrow) {
745ffd83dbSDimitry Andric     if (smartptr::isNullSmartPtr(State, ThisRegion))
75*e8d8bef9SDimitry Andric       reportBug(C, ThisRegion, Call);
765ffd83dbSDimitry Andric   }
775ffd83dbSDimitry Andric }
785ffd83dbSDimitry Andric 
reportBug(CheckerContext & C,const MemRegion * DerefRegion,const CallEvent & Call) const79*e8d8bef9SDimitry Andric void SmartPtrChecker::reportBug(CheckerContext &C, const MemRegion *DerefRegion,
805ffd83dbSDimitry Andric                                 const CallEvent &Call) const {
815ffd83dbSDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode();
825ffd83dbSDimitry Andric   if (!ErrNode)
835ffd83dbSDimitry Andric     return;
84*e8d8bef9SDimitry Andric   llvm::SmallString<128> Str;
85*e8d8bef9SDimitry Andric   llvm::raw_svector_ostream OS(Str);
86*e8d8bef9SDimitry Andric   explainDereference(OS, DerefRegion, Call);
87*e8d8bef9SDimitry Andric   auto R = std::make_unique<PathSensitiveBugReport>(NullDereferenceBugType,
88*e8d8bef9SDimitry Andric                                                     OS.str(), ErrNode);
89*e8d8bef9SDimitry Andric   R->markInteresting(DerefRegion);
905ffd83dbSDimitry Andric   C.emitReport(std::move(R));
915ffd83dbSDimitry Andric }
925ffd83dbSDimitry Andric 
explainDereference(llvm::raw_ostream & OS,const MemRegion * DerefRegion,const CallEvent & Call) const93*e8d8bef9SDimitry Andric void SmartPtrChecker::explainDereference(llvm::raw_ostream &OS,
94*e8d8bef9SDimitry Andric                                          const MemRegion *DerefRegion,
95*e8d8bef9SDimitry Andric                                          const CallEvent &Call) const {
96*e8d8bef9SDimitry Andric   OS << "Dereference of null smart pointer ";
97*e8d8bef9SDimitry Andric   DerefRegion->printPretty(OS);
98*e8d8bef9SDimitry Andric }
99*e8d8bef9SDimitry Andric 
registerSmartPtrChecker(CheckerManager & Mgr)1005ffd83dbSDimitry Andric void ento::registerSmartPtrChecker(CheckerManager &Mgr) {
101*e8d8bef9SDimitry Andric   SmartPtrChecker *Checker = Mgr.registerChecker<SmartPtrChecker>();
102*e8d8bef9SDimitry Andric   NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
1035ffd83dbSDimitry Andric }
1045ffd83dbSDimitry Andric 
shouldRegisterSmartPtrChecker(const CheckerManager & mgr)1055ffd83dbSDimitry Andric bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {
1065ffd83dbSDimitry Andric   const LangOptions &LO = mgr.getLangOpts();
1075ffd83dbSDimitry Andric   return LO.CPlusPlus;
1085ffd83dbSDimitry Andric }
109