105 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines a checker that check for null dereference of C++ smart10// pointer.11//12//===----------------------------------------------------------------------===//13#include "SmartPtr.h"14 15#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"16#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"17#include "clang/StaticAnalyzer/Core/Checker.h"18#include "clang/StaticAnalyzer/Core/CheckerManager.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"20#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"21#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"22#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"23 24using namespace clang;25using namespace ento;26 27namespace {28 29static const BugType *NullDereferenceBugTypePtr;30 31class SmartPtrChecker : public Checker<check::PreCall> {32public:33 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;34 BugType NullDereferenceBugType{this, "Null SmartPtr dereference",35 "C++ Smart Pointer"};36 37private:38 void reportBug(CheckerContext &C, const MemRegion *DerefRegion,39 const CallEvent &Call) const;40 void explainDereference(llvm::raw_ostream &OS, const MemRegion *DerefRegion,41 const CallEvent &Call) const;42};43} // end of anonymous namespace44 45// Define the inter-checker API.46namespace clang {47namespace ento {48namespace smartptr {49 50const BugType *getNullDereferenceBugType() { return NullDereferenceBugTypePtr; }51 52} // namespace smartptr53} // namespace ento54} // namespace clang55 56void SmartPtrChecker::checkPreCall(const CallEvent &Call,57 CheckerContext &C) const {58 if (!smartptr::isStdSmartPtrCall(Call))59 return;60 ProgramStateRef State = C.getState();61 const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);62 if (!OC)63 return;64 const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();65 if (!ThisRegion)66 return;67 68 OverloadedOperatorKind OOK = OC->getOverloadedOperator();69 if (OOK == OO_Star || OOK == OO_Arrow) {70 if (smartptr::isNullSmartPtr(State, ThisRegion))71 reportBug(C, ThisRegion, Call);72 }73}74 75void SmartPtrChecker::reportBug(CheckerContext &C, const MemRegion *DerefRegion,76 const CallEvent &Call) const {77 ExplodedNode *ErrNode = C.generateErrorNode();78 if (!ErrNode)79 return;80 llvm::SmallString<128> Str;81 llvm::raw_svector_ostream OS(Str);82 explainDereference(OS, DerefRegion, Call);83 auto R = std::make_unique<PathSensitiveBugReport>(NullDereferenceBugType,84 OS.str(), ErrNode);85 R->markInteresting(DerefRegion);86 C.emitReport(std::move(R));87}88 89void SmartPtrChecker::explainDereference(llvm::raw_ostream &OS,90 const MemRegion *DerefRegion,91 const CallEvent &Call) const {92 OS << "Dereference of null smart pointer ";93 DerefRegion->printPretty(OS);94}95 96void ento::registerSmartPtrChecker(CheckerManager &Mgr) {97 SmartPtrChecker *Checker = Mgr.registerChecker<SmartPtrChecker>();98 NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;99}100 101bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {102 const LangOptions &LO = mgr.getLangOpts();103 return LO.CPlusPlus;104}105