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