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