1 // SmartPtrChecker.cpp - Check for smart pointer dereference - C++ --------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines a checker that check for null dereference of C++ smart
12 //===----------------------------------------------------------------------===//
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 #include "llvm/ADT/StringRef.h"
28 using namespace clang
;
33 static const BugType
*NullDereferenceBugTypePtr
;
35 class SmartPtrChecker
: public Checker
<check::PreCall
> {
37 void checkPreCall(const CallEvent
&Call
, CheckerContext
&C
) const;
38 BugType NullDereferenceBugType
{this, "Null SmartPtr dereference",
42 void reportBug(CheckerContext
&C
, const MemRegion
*DerefRegion
,
43 const CallEvent
&Call
) const;
44 void explainDereference(llvm::raw_ostream
&OS
, const MemRegion
*DerefRegion
,
45 const CallEvent
&Call
) const;
47 } // end of anonymous namespace
49 // Define the inter-checker API.
54 const BugType
*getNullDereferenceBugType() { return NullDereferenceBugTypePtr
; }
56 } // namespace smartptr
60 void SmartPtrChecker::checkPreCall(const CallEvent
&Call
,
61 CheckerContext
&C
) const {
62 if (!smartptr::isStdSmartPtrCall(Call
))
64 ProgramStateRef State
= C
.getState();
65 const auto *OC
= dyn_cast
<CXXMemberOperatorCall
>(&Call
);
68 const MemRegion
*ThisRegion
= OC
->getCXXThisVal().getAsRegion();
72 OverloadedOperatorKind OOK
= OC
->getOverloadedOperator();
73 if (OOK
== OO_Star
|| OOK
== OO_Arrow
) {
74 if (smartptr::isNullSmartPtr(State
, ThisRegion
))
75 reportBug(C
, ThisRegion
, Call
);
79 void SmartPtrChecker::reportBug(CheckerContext
&C
, const MemRegion
*DerefRegion
,
80 const CallEvent
&Call
) const {
81 ExplodedNode
*ErrNode
= C
.generateErrorNode();
84 llvm::SmallString
<128> Str
;
85 llvm::raw_svector_ostream
OS(Str
);
86 explainDereference(OS
, DerefRegion
, Call
);
87 auto R
= std::make_unique
<PathSensitiveBugReport
>(NullDereferenceBugType
,
89 R
->markInteresting(DerefRegion
);
90 C
.emitReport(std::move(R
));
93 void SmartPtrChecker::explainDereference(llvm::raw_ostream
&OS
,
94 const MemRegion
*DerefRegion
,
95 const CallEvent
&Call
) const {
96 OS
<< "Dereference of null smart pointer ";
97 DerefRegion
->printPretty(OS
);
100 void ento::registerSmartPtrChecker(CheckerManager
&Mgr
) {
101 SmartPtrChecker
*Checker
= Mgr
.registerChecker
<SmartPtrChecker
>();
102 NullDereferenceBugTypePtr
= &Checker
->NullDereferenceBugType
;
105 bool ento::shouldRegisterSmartPtrChecker(const CheckerManager
&mgr
) {
106 const LangOptions
&LO
= mgr
.getLangOpts();