xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric // SmartPtrChecker.cpp - Check for smart pointer dereference - C++ --------===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric //
9*5ffd83dbSDimitry Andric // This file defines a checker that check for null dereference of C++ smart
10*5ffd83dbSDimitry Andric // pointer.
11*5ffd83dbSDimitry Andric //
12*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
13*5ffd83dbSDimitry Andric #include "SmartPtr.h"
14*5ffd83dbSDimitry Andric 
15*5ffd83dbSDimitry Andric #include "clang/AST/DeclCXX.h"
16*5ffd83dbSDimitry Andric #include "clang/AST/ExprCXX.h"
17*5ffd83dbSDimitry Andric #include "clang/AST/Type.h"
18*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
19*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
21*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
22*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
23*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
25*5ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
26*5ffd83dbSDimitry Andric 
27*5ffd83dbSDimitry Andric using namespace clang;
28*5ffd83dbSDimitry Andric using namespace ento;
29*5ffd83dbSDimitry Andric 
30*5ffd83dbSDimitry Andric namespace {
31*5ffd83dbSDimitry Andric class SmartPtrChecker : public Checker<check::PreCall> {
32*5ffd83dbSDimitry Andric   BugType NullDereferenceBugType{this, "Null SmartPtr dereference",
33*5ffd83dbSDimitry Andric                                  "C++ Smart Pointer"};
34*5ffd83dbSDimitry Andric 
35*5ffd83dbSDimitry Andric public:
36*5ffd83dbSDimitry Andric   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
37*5ffd83dbSDimitry Andric 
38*5ffd83dbSDimitry Andric private:
39*5ffd83dbSDimitry Andric   void reportBug(CheckerContext &C, const CallEvent &Call) const;
40*5ffd83dbSDimitry Andric };
41*5ffd83dbSDimitry Andric } // end of anonymous namespace
42*5ffd83dbSDimitry Andric 
43*5ffd83dbSDimitry Andric void SmartPtrChecker::checkPreCall(const CallEvent &Call,
44*5ffd83dbSDimitry Andric                                    CheckerContext &C) const {
45*5ffd83dbSDimitry Andric   if (!smartptr::isStdSmartPtrCall(Call))
46*5ffd83dbSDimitry Andric     return;
47*5ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
48*5ffd83dbSDimitry Andric   const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
49*5ffd83dbSDimitry Andric   if (!OC)
50*5ffd83dbSDimitry Andric     return;
51*5ffd83dbSDimitry Andric   const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
52*5ffd83dbSDimitry Andric   if (!ThisRegion)
53*5ffd83dbSDimitry Andric     return;
54*5ffd83dbSDimitry Andric 
55*5ffd83dbSDimitry Andric   OverloadedOperatorKind OOK = OC->getOverloadedOperator();
56*5ffd83dbSDimitry Andric   if (OOK == OO_Star || OOK == OO_Arrow) {
57*5ffd83dbSDimitry Andric     if (smartptr::isNullSmartPtr(State, ThisRegion))
58*5ffd83dbSDimitry Andric       reportBug(C, Call);
59*5ffd83dbSDimitry Andric   }
60*5ffd83dbSDimitry Andric }
61*5ffd83dbSDimitry Andric 
62*5ffd83dbSDimitry Andric void SmartPtrChecker::reportBug(CheckerContext &C,
63*5ffd83dbSDimitry Andric                                 const CallEvent &Call) const {
64*5ffd83dbSDimitry Andric   ExplodedNode *ErrNode = C.generateErrorNode();
65*5ffd83dbSDimitry Andric   if (!ErrNode)
66*5ffd83dbSDimitry Andric     return;
67*5ffd83dbSDimitry Andric 
68*5ffd83dbSDimitry Andric   auto R = std::make_unique<PathSensitiveBugReport>(
69*5ffd83dbSDimitry Andric       NullDereferenceBugType, "Dereference of null smart pointer", ErrNode);
70*5ffd83dbSDimitry Andric   C.emitReport(std::move(R));
71*5ffd83dbSDimitry Andric }
72*5ffd83dbSDimitry Andric 
73*5ffd83dbSDimitry Andric void ento::registerSmartPtrChecker(CheckerManager &Mgr) {
74*5ffd83dbSDimitry Andric   Mgr.registerChecker<SmartPtrChecker>();
75*5ffd83dbSDimitry Andric }
76*5ffd83dbSDimitry Andric 
77*5ffd83dbSDimitry Andric bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {
78*5ffd83dbSDimitry Andric   const LangOptions &LO = mgr.getLangOpts();
79*5ffd83dbSDimitry Andric   return LO.CPlusPlus;
80*5ffd83dbSDimitry Andric }
81