120e271a9SNithin Vadukkumchery Rajendrakumar // SmartPtrChecker.cpp - Check for smart pointer dereference - C++ --------===//
220e271a9SNithin Vadukkumchery Rajendrakumar //
320e271a9SNithin Vadukkumchery Rajendrakumar // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
420e271a9SNithin Vadukkumchery Rajendrakumar // See https://llvm.org/LICENSE.txt for license information.
520e271a9SNithin Vadukkumchery Rajendrakumar // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
620e271a9SNithin Vadukkumchery Rajendrakumar //
720e271a9SNithin Vadukkumchery Rajendrakumar //===----------------------------------------------------------------------===//
820e271a9SNithin Vadukkumchery Rajendrakumar //
920e271a9SNithin Vadukkumchery Rajendrakumar // This file defines a checker that check for null dereference of C++ smart
1020e271a9SNithin Vadukkumchery Rajendrakumar // pointer.
1120e271a9SNithin Vadukkumchery Rajendrakumar //
1220e271a9SNithin Vadukkumchery Rajendrakumar //===----------------------------------------------------------------------===//
1320e271a9SNithin Vadukkumchery Rajendrakumar #include "SmartPtr.h"
1420e271a9SNithin Vadukkumchery Rajendrakumar
1520e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/DeclCXX.h"
1620e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/ExprCXX.h"
1720e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/Type.h"
1820e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
1920e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
2020e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/Checker.h"
2120e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/CheckerManager.h"
2220e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
2320e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2420e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
2520e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
26*06d100a6SNithin Vadukkumchery Rajendrakumar #include "llvm/ADT/StringRef.h"
2720e271a9SNithin Vadukkumchery Rajendrakumar
2820e271a9SNithin Vadukkumchery Rajendrakumar using namespace clang;
2920e271a9SNithin Vadukkumchery Rajendrakumar using namespace ento;
3020e271a9SNithin Vadukkumchery Rajendrakumar
3120e271a9SNithin Vadukkumchery Rajendrakumar namespace {
32*06d100a6SNithin Vadukkumchery Rajendrakumar
33*06d100a6SNithin Vadukkumchery Rajendrakumar static const BugType *NullDereferenceBugTypePtr;
34*06d100a6SNithin Vadukkumchery Rajendrakumar
3520e271a9SNithin Vadukkumchery Rajendrakumar class SmartPtrChecker : public Checker<check::PreCall> {
36*06d100a6SNithin Vadukkumchery Rajendrakumar public:
37*06d100a6SNithin Vadukkumchery Rajendrakumar void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
3820e271a9SNithin Vadukkumchery Rajendrakumar BugType NullDereferenceBugType{this, "Null SmartPtr dereference",
3920e271a9SNithin Vadukkumchery Rajendrakumar "C++ Smart Pointer"};
4020e271a9SNithin Vadukkumchery Rajendrakumar
4120e271a9SNithin Vadukkumchery Rajendrakumar private:
42*06d100a6SNithin Vadukkumchery Rajendrakumar void reportBug(CheckerContext &C, const MemRegion *DerefRegion,
43*06d100a6SNithin Vadukkumchery Rajendrakumar const CallEvent &Call) const;
44*06d100a6SNithin Vadukkumchery Rajendrakumar void explainDereference(llvm::raw_ostream &OS, const MemRegion *DerefRegion,
45*06d100a6SNithin Vadukkumchery Rajendrakumar const CallEvent &Call) const;
4620e271a9SNithin Vadukkumchery Rajendrakumar };
4720e271a9SNithin Vadukkumchery Rajendrakumar } // end of anonymous namespace
4820e271a9SNithin Vadukkumchery Rajendrakumar
49*06d100a6SNithin Vadukkumchery Rajendrakumar // Define the inter-checker API.
50*06d100a6SNithin Vadukkumchery Rajendrakumar namespace clang {
51*06d100a6SNithin Vadukkumchery Rajendrakumar namespace ento {
52*06d100a6SNithin Vadukkumchery Rajendrakumar namespace smartptr {
53*06d100a6SNithin Vadukkumchery Rajendrakumar
getNullDereferenceBugType()54*06d100a6SNithin Vadukkumchery Rajendrakumar const BugType *getNullDereferenceBugType() { return NullDereferenceBugTypePtr; }
55*06d100a6SNithin Vadukkumchery Rajendrakumar
56*06d100a6SNithin Vadukkumchery Rajendrakumar } // namespace smartptr
57*06d100a6SNithin Vadukkumchery Rajendrakumar } // namespace ento
58*06d100a6SNithin Vadukkumchery Rajendrakumar } // namespace clang
59*06d100a6SNithin Vadukkumchery Rajendrakumar
checkPreCall(const CallEvent & Call,CheckerContext & C) const6020e271a9SNithin Vadukkumchery Rajendrakumar void SmartPtrChecker::checkPreCall(const CallEvent &Call,
6120e271a9SNithin Vadukkumchery Rajendrakumar CheckerContext &C) const {
6220e271a9SNithin Vadukkumchery Rajendrakumar if (!smartptr::isStdSmartPtrCall(Call))
6320e271a9SNithin Vadukkumchery Rajendrakumar return;
6420e271a9SNithin Vadukkumchery Rajendrakumar ProgramStateRef State = C.getState();
6520e271a9SNithin Vadukkumchery Rajendrakumar const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
6620e271a9SNithin Vadukkumchery Rajendrakumar if (!OC)
6720e271a9SNithin Vadukkumchery Rajendrakumar return;
6820e271a9SNithin Vadukkumchery Rajendrakumar const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
6920e271a9SNithin Vadukkumchery Rajendrakumar if (!ThisRegion)
7020e271a9SNithin Vadukkumchery Rajendrakumar return;
7120e271a9SNithin Vadukkumchery Rajendrakumar
7220e271a9SNithin Vadukkumchery Rajendrakumar OverloadedOperatorKind OOK = OC->getOverloadedOperator();
7320e271a9SNithin Vadukkumchery Rajendrakumar if (OOK == OO_Star || OOK == OO_Arrow) {
7420e271a9SNithin Vadukkumchery Rajendrakumar if (smartptr::isNullSmartPtr(State, ThisRegion))
75*06d100a6SNithin Vadukkumchery Rajendrakumar reportBug(C, ThisRegion, Call);
7620e271a9SNithin Vadukkumchery Rajendrakumar }
7720e271a9SNithin Vadukkumchery Rajendrakumar }
7820e271a9SNithin Vadukkumchery Rajendrakumar
reportBug(CheckerContext & C,const MemRegion * DerefRegion,const CallEvent & Call) const79*06d100a6SNithin Vadukkumchery Rajendrakumar void SmartPtrChecker::reportBug(CheckerContext &C, const MemRegion *DerefRegion,
8020e271a9SNithin Vadukkumchery Rajendrakumar const CallEvent &Call) const {
8120e271a9SNithin Vadukkumchery Rajendrakumar ExplodedNode *ErrNode = C.generateErrorNode();
8220e271a9SNithin Vadukkumchery Rajendrakumar if (!ErrNode)
8320e271a9SNithin Vadukkumchery Rajendrakumar return;
84*06d100a6SNithin Vadukkumchery Rajendrakumar llvm::SmallString<128> Str;
85*06d100a6SNithin Vadukkumchery Rajendrakumar llvm::raw_svector_ostream OS(Str);
86*06d100a6SNithin Vadukkumchery Rajendrakumar explainDereference(OS, DerefRegion, Call);
87*06d100a6SNithin Vadukkumchery Rajendrakumar auto R = std::make_unique<PathSensitiveBugReport>(NullDereferenceBugType,
88*06d100a6SNithin Vadukkumchery Rajendrakumar OS.str(), ErrNode);
89*06d100a6SNithin Vadukkumchery Rajendrakumar R->markInteresting(DerefRegion);
9020e271a9SNithin Vadukkumchery Rajendrakumar C.emitReport(std::move(R));
9120e271a9SNithin Vadukkumchery Rajendrakumar }
9220e271a9SNithin Vadukkumchery Rajendrakumar
explainDereference(llvm::raw_ostream & OS,const MemRegion * DerefRegion,const CallEvent & Call) const93*06d100a6SNithin Vadukkumchery Rajendrakumar void SmartPtrChecker::explainDereference(llvm::raw_ostream &OS,
94*06d100a6SNithin Vadukkumchery Rajendrakumar const MemRegion *DerefRegion,
95*06d100a6SNithin Vadukkumchery Rajendrakumar const CallEvent &Call) const {
96*06d100a6SNithin Vadukkumchery Rajendrakumar OS << "Dereference of null smart pointer ";
97*06d100a6SNithin Vadukkumchery Rajendrakumar DerefRegion->printPretty(OS);
98*06d100a6SNithin Vadukkumchery Rajendrakumar }
99*06d100a6SNithin Vadukkumchery Rajendrakumar
registerSmartPtrChecker(CheckerManager & Mgr)10020e271a9SNithin Vadukkumchery Rajendrakumar void ento::registerSmartPtrChecker(CheckerManager &Mgr) {
101*06d100a6SNithin Vadukkumchery Rajendrakumar SmartPtrChecker *Checker = Mgr.registerChecker<SmartPtrChecker>();
102*06d100a6SNithin Vadukkumchery Rajendrakumar NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
10320e271a9SNithin Vadukkumchery Rajendrakumar }
10420e271a9SNithin Vadukkumchery Rajendrakumar
shouldRegisterSmartPtrChecker(const CheckerManager & mgr)10520e271a9SNithin Vadukkumchery Rajendrakumar bool ento::shouldRegisterSmartPtrChecker(const CheckerManager &mgr) {
10620e271a9SNithin Vadukkumchery Rajendrakumar const LangOptions &LO = mgr.getLangOpts();
10720e271a9SNithin Vadukkumchery Rajendrakumar return LO.CPlusPlus;
10820e271a9SNithin Vadukkumchery Rajendrakumar }
109