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 15 #include "clang/AST/DeclCXX.h" 16 #include "clang/AST/ExprCXX.h" 17 #include "clang/AST/Type.h" 18 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20 #include "clang/StaticAnalyzer/Core/Checker.h" 21 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 25 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" 26 27 using namespace clang; 28 using namespace ento; 29 30 namespace { 31 class SmartPtrChecker : public Checker<check::PreCall> { 32 BugType NullDereferenceBugType{this, "Null SmartPtr dereference", 33 "C++ Smart Pointer"}; 34 35 public: 36 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 37 38 private: 39 void reportBug(CheckerContext &C, const CallEvent &Call) const; 40 }; 41 } // end of anonymous namespace 42 43 void SmartPtrChecker::checkPreCall(const CallEvent &Call, 44 CheckerContext &C) const { 45 if (!smartptr::isStdSmartPtrCall(Call)) 46 return; 47 ProgramStateRef State = C.getState(); 48 const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call); 49 if (!OC) 50 return; 51 const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion(); 52 if (!ThisRegion) 53 return; 54 55 OverloadedOperatorKind OOK = OC->getOverloadedOperator(); 56 if (OOK == OO_Star || OOK == OO_Arrow) { 57 if (smartptr::isNullSmartPtr(State, ThisRegion)) 58 reportBug(C, Call); 59 } 60 } 61 62 void SmartPtrChecker::reportBug(CheckerContext &C, 63 const CallEvent &Call) const { 64 ExplodedNode *ErrNode = C.generateErrorNode(); 65 if (!ErrNode) 66 return; 67 68 auto R = std::make_unique<PathSensitiveBugReport>( 69 NullDereferenceBugType, "Dereference of null smart pointer", ErrNode); 70 C.emitReport(std::move(R)); 71 } 72 73 void ento::registerSmartPtrChecker(CheckerManager &Mgr) { 74 Mgr.registerChecker<SmartPtrChecker>(); 75 } 76 77 bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) { 78 const LangOptions &LO = mgr.getLangOpts(); 79 return LO.CPlusPlus; 80 } 81