18c6119a4SArtem Dergachev // SmartPtrModeling.cpp - Model behavior of C++ smart pointers - C++ ------===//
28c6119a4SArtem Dergachev //
38c6119a4SArtem Dergachev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48c6119a4SArtem Dergachev // See https://llvm.org/LICENSE.txt for license information.
58c6119a4SArtem Dergachev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68c6119a4SArtem Dergachev //
78c6119a4SArtem Dergachev //===----------------------------------------------------------------------===//
88c6119a4SArtem Dergachev //
98c6119a4SArtem Dergachev // This file defines a checker that models various aspects of
108c6119a4SArtem Dergachev // C++ smart pointer behavior.
118c6119a4SArtem Dergachev //
128c6119a4SArtem Dergachev //===----------------------------------------------------------------------===//
138c6119a4SArtem Dergachev 
148c6119a4SArtem Dergachev #include "Move.h"
1520e271a9SNithin Vadukkumchery Rajendrakumar #include "SmartPtr.h"
168c6119a4SArtem Dergachev 
1720e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/DeclCXX.h"
18bc3d4d9eSNithin Vadukkumchery Rajendrakumar #include "clang/AST/DeclarationName.h"
198c6119a4SArtem Dergachev #include "clang/AST/ExprCXX.h"
2020e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/AST/Type.h"
2106d100a6SNithin Vadukkumchery Rajendrakumar #include "clang/Basic/LLVM.h"
228c6119a4SArtem Dergachev #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
238c6119a4SArtem Dergachev #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
248c6119a4SArtem Dergachev #include "clang/StaticAnalyzer/Core/Checker.h"
258c6119a4SArtem Dergachev #include "clang/StaticAnalyzer/Core/CheckerManager.h"
260b9d3a6eSBalazs Benics #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
278c6119a4SArtem Dergachev #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
288c6119a4SArtem Dergachev #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2948688257SDeep Majumder #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
3006d100a6SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
3120e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
3220e271a9SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
3306d100a6SNithin Vadukkumchery Rajendrakumar #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
3448688257SDeep Majumder #include "llvm/ADT/StringMap.h"
3548688257SDeep Majumder #include "llvm/Support/ErrorHandling.h"
3606d100a6SNithin Vadukkumchery Rajendrakumar #include <string>
378c6119a4SArtem Dergachev 
388c6119a4SArtem Dergachev using namespace clang;
398c6119a4SArtem Dergachev using namespace ento;
408c6119a4SArtem Dergachev 
418c6119a4SArtem Dergachev namespace {
42d8253093SDeep Majumder 
43a5609102SNithin Vadukkumchery Rajendrakumar class SmartPtrModeling
44bc3d4d9eSNithin Vadukkumchery Rajendrakumar     : public Checker<eval::Call, check::DeadSymbols, check::RegionChanges,
45bc3d4d9eSNithin Vadukkumchery Rajendrakumar                      check::LiveSymbols> {
4620e271a9SNithin Vadukkumchery Rajendrakumar 
47bc3d4d9eSNithin Vadukkumchery Rajendrakumar   bool isBoolConversionMethod(const CallEvent &Call) const;
488c6119a4SArtem Dergachev 
498c6119a4SArtem Dergachev public:
5020e271a9SNithin Vadukkumchery Rajendrakumar   // Whether the checker should model for null dereferences of smart pointers.
51*5114db93SVince Bridgers   bool ModelSmartPtrDereference = false;
5244820630SArtem Dergachev   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
5320e271a9SNithin Vadukkumchery Rajendrakumar   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
54a5609102SNithin Vadukkumchery Rajendrakumar   ProgramStateRef
55a5609102SNithin Vadukkumchery Rajendrakumar   checkRegionChanges(ProgramStateRef State,
56a5609102SNithin Vadukkumchery Rajendrakumar                      const InvalidatedSymbols *Invalidated,
57a5609102SNithin Vadukkumchery Rajendrakumar                      ArrayRef<const MemRegion *> ExplicitRegions,
58a5609102SNithin Vadukkumchery Rajendrakumar                      ArrayRef<const MemRegion *> Regions,
59a5609102SNithin Vadukkumchery Rajendrakumar                      const LocationContext *LCtx, const CallEvent *Call) const;
60bc3d4d9eSNithin Vadukkumchery Rajendrakumar   void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
61d563d7a7SHubert Tong                   const char *Sep) const override;
62bc3d4d9eSNithin Vadukkumchery Rajendrakumar   void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const;
6320e271a9SNithin Vadukkumchery Rajendrakumar 
6420e271a9SNithin Vadukkumchery Rajendrakumar private:
6520e271a9SNithin Vadukkumchery Rajendrakumar   void handleReset(const CallEvent &Call, CheckerContext &C) const;
6620e271a9SNithin Vadukkumchery Rajendrakumar   void handleRelease(const CallEvent &Call, CheckerContext &C) const;
670cd98befSDeep Majumder   void handleSwapMethod(const CallEvent &Call, CheckerContext &C) const;
6855208f5aSNithin Vadukkumchery Rajendrakumar   void handleGet(const CallEvent &Call, CheckerContext &C) const;
6920676cabSNithin Vadukkumchery Rajendrakumar   bool handleAssignOp(const CallEvent &Call, CheckerContext &C) const;
701b743a9eSNithin Vadukkumchery Rajendrakumar   bool handleMoveCtr(const CallEvent &Call, CheckerContext &C,
711b743a9eSNithin Vadukkumchery Rajendrakumar                      const MemRegion *ThisRegion) const;
721b743a9eSNithin Vadukkumchery Rajendrakumar   bool updateMovedSmartPointers(CheckerContext &C, const MemRegion *ThisRegion,
7398588841SVince Bridgers                                 const MemRegion *OtherSmartPtrRegion,
7498588841SVince Bridgers                                 const CallEvent &Call) const;
75bc3d4d9eSNithin Vadukkumchery Rajendrakumar   void handleBoolConversion(const CallEvent &Call, CheckerContext &C) const;
7648688257SDeep Majumder   bool handleComparisionOp(const CallEvent &Call, CheckerContext &C) const;
7713fe7821SDeep Majumder   bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const;
780cd98befSDeep Majumder   bool handleSwap(ProgramStateRef State, SVal First, SVal Second,
790cd98befSDeep Majumder                   CheckerContext &C) const;
8048688257SDeep Majumder   std::pair<SVal, ProgramStateRef>
8148688257SDeep Majumder   retrieveOrConjureInnerPtrVal(ProgramStateRef State,
8248688257SDeep Majumder                                const MemRegion *ThisRegion, const Expr *E,
8348688257SDeep Majumder                                QualType Type, CheckerContext &C) const;
8420e271a9SNithin Vadukkumchery Rajendrakumar 
8520e271a9SNithin Vadukkumchery Rajendrakumar   using SmartPtrMethodHandlerFn =
8620e271a9SNithin Vadukkumchery Rajendrakumar       void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
8720e271a9SNithin Vadukkumchery Rajendrakumar   CallDescriptionMap<SmartPtrMethodHandlerFn> SmartPtrMethodHandlers{
8820e271a9SNithin Vadukkumchery Rajendrakumar       {{"reset"}, &SmartPtrModeling::handleReset},
8920e271a9SNithin Vadukkumchery Rajendrakumar       {{"release"}, &SmartPtrModeling::handleRelease},
900cd98befSDeep Majumder       {{"swap", 1}, &SmartPtrModeling::handleSwapMethod},
9155208f5aSNithin Vadukkumchery Rajendrakumar       {{"get"}, &SmartPtrModeling::handleGet}};
920cd98befSDeep Majumder   const CallDescription StdSwapCall{{"std", "swap"}, 2};
93d8253093SDeep Majumder   const CallDescription StdMakeUniqueCall{{"std", "make_unique"}};
94d8253093SDeep Majumder   const CallDescription StdMakeUniqueForOverwriteCall{
95d8253093SDeep Majumder       {"std", "make_unique_for_overwrite"}};
968c6119a4SArtem Dergachev };
978c6119a4SArtem Dergachev } // end of anonymous namespace
988c6119a4SArtem Dergachev 
REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap,const MemRegion *,SVal)9920e271a9SNithin Vadukkumchery Rajendrakumar REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, SVal)
10020e271a9SNithin Vadukkumchery Rajendrakumar 
10113fe7821SDeep Majumder // Checks if RD has name in Names and is in std namespace
10213fe7821SDeep Majumder static bool hasStdClassWithName(const CXXRecordDecl *RD,
10313fe7821SDeep Majumder                                 ArrayRef<llvm::StringLiteral> Names) {
10413fe7821SDeep Majumder   if (!RD || !RD->getDeclContext()->isStdNamespace())
10513fe7821SDeep Majumder     return false;
1066a154e60SKazu Hirata   if (RD->getDeclName().isIdentifier())
1076a154e60SKazu Hirata     return llvm::is_contained(Names, RD->getName());
10813fe7821SDeep Majumder   return false;
10913fe7821SDeep Majumder }
11013fe7821SDeep Majumder 
11113fe7821SDeep Majumder constexpr llvm::StringLiteral STD_PTR_NAMES[] = {"shared_ptr", "unique_ptr",
11213fe7821SDeep Majumder                                                  "weak_ptr"};
11313fe7821SDeep Majumder 
isStdSmartPtr(const CXXRecordDecl * RD)11413fe7821SDeep Majumder static bool isStdSmartPtr(const CXXRecordDecl *RD) {
11513fe7821SDeep Majumder   return hasStdClassWithName(RD, STD_PTR_NAMES);
11613fe7821SDeep Majumder }
11713fe7821SDeep Majumder 
isStdSmartPtr(const Expr * E)11813fe7821SDeep Majumder static bool isStdSmartPtr(const Expr *E) {
11913fe7821SDeep Majumder   return isStdSmartPtr(E->getType()->getAsCXXRecordDecl());
12013fe7821SDeep Majumder }
12113fe7821SDeep Majumder 
12220e271a9SNithin Vadukkumchery Rajendrakumar // Define the inter-checker API.
12320e271a9SNithin Vadukkumchery Rajendrakumar namespace clang {
12420e271a9SNithin Vadukkumchery Rajendrakumar namespace ento {
12520e271a9SNithin Vadukkumchery Rajendrakumar namespace smartptr {
isStdSmartPtrCall(const CallEvent & Call)12620e271a9SNithin Vadukkumchery Rajendrakumar bool isStdSmartPtrCall(const CallEvent &Call) {
12720e271a9SNithin Vadukkumchery Rajendrakumar   const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
12820e271a9SNithin Vadukkumchery Rajendrakumar   if (!MethodDecl || !MethodDecl->getParent())
12920e271a9SNithin Vadukkumchery Rajendrakumar     return false;
13048688257SDeep Majumder   return isStdSmartPtr(MethodDecl->getParent());
13148688257SDeep Majumder }
13220e271a9SNithin Vadukkumchery Rajendrakumar 
isStdSmartPtr(const CXXRecordDecl * RD)13348688257SDeep Majumder bool isStdSmartPtr(const CXXRecordDecl *RD) {
13448688257SDeep Majumder   if (!RD || !RD->getDeclContext()->isStdNamespace())
13520e271a9SNithin Vadukkumchery Rajendrakumar     return false;
13620e271a9SNithin Vadukkumchery Rajendrakumar 
13748688257SDeep Majumder   if (RD->getDeclName().isIdentifier()) {
13848688257SDeep Majumder     StringRef Name = RD->getName();
139724afa5aSBenjamin Kramer     return Name == "shared_ptr" || Name == "unique_ptr" || Name == "weak_ptr";
14020e271a9SNithin Vadukkumchery Rajendrakumar   }
14120e271a9SNithin Vadukkumchery Rajendrakumar   return false;
14220e271a9SNithin Vadukkumchery Rajendrakumar }
14320e271a9SNithin Vadukkumchery Rajendrakumar 
isStdSmartPtr(const Expr * E)14448688257SDeep Majumder bool isStdSmartPtr(const Expr *E) {
14548688257SDeep Majumder   return isStdSmartPtr(E->getType()->getAsCXXRecordDecl());
14648688257SDeep Majumder }
14748688257SDeep Majumder 
isNullSmartPtr(const ProgramStateRef State,const MemRegion * ThisRegion)14820e271a9SNithin Vadukkumchery Rajendrakumar bool isNullSmartPtr(const ProgramStateRef State, const MemRegion *ThisRegion) {
14920e271a9SNithin Vadukkumchery Rajendrakumar   const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
1500b4fe808SNithin Vadukkumchery Rajendrakumar   return InnerPointVal &&
1510b4fe808SNithin Vadukkumchery Rajendrakumar          !State->assume(InnerPointVal->castAs<DefinedOrUnknownSVal>(), true);
15220e271a9SNithin Vadukkumchery Rajendrakumar }
15320e271a9SNithin Vadukkumchery Rajendrakumar } // namespace smartptr
15420e271a9SNithin Vadukkumchery Rajendrakumar } // namespace ento
15520e271a9SNithin Vadukkumchery Rajendrakumar } // namespace clang
15620e271a9SNithin Vadukkumchery Rajendrakumar 
157a5609102SNithin Vadukkumchery Rajendrakumar // If a region is removed all of the subregions need to be removed too.
158a5609102SNithin Vadukkumchery Rajendrakumar static TrackedRegionMapTy
removeTrackedSubregions(TrackedRegionMapTy RegionMap,TrackedRegionMapTy::Factory & RegionMapFactory,const MemRegion * Region)159a5609102SNithin Vadukkumchery Rajendrakumar removeTrackedSubregions(TrackedRegionMapTy RegionMap,
160a5609102SNithin Vadukkumchery Rajendrakumar                         TrackedRegionMapTy::Factory &RegionMapFactory,
161a5609102SNithin Vadukkumchery Rajendrakumar                         const MemRegion *Region) {
162a5609102SNithin Vadukkumchery Rajendrakumar   if (!Region)
163a5609102SNithin Vadukkumchery Rajendrakumar     return RegionMap;
164a5609102SNithin Vadukkumchery Rajendrakumar   for (const auto &E : RegionMap) {
165a5609102SNithin Vadukkumchery Rajendrakumar     if (E.first->isSubRegionOf(Region))
166a5609102SNithin Vadukkumchery Rajendrakumar       RegionMap = RegionMapFactory.remove(RegionMap, E.first);
167a5609102SNithin Vadukkumchery Rajendrakumar   }
168a5609102SNithin Vadukkumchery Rajendrakumar   return RegionMap;
169a5609102SNithin Vadukkumchery Rajendrakumar }
170a5609102SNithin Vadukkumchery Rajendrakumar 
updateSwappedRegion(ProgramStateRef State,const MemRegion * Region,const SVal * RegionInnerPointerVal)17176c05777SNithin Vadukkumchery Rajendrakumar static ProgramStateRef updateSwappedRegion(ProgramStateRef State,
17276c05777SNithin Vadukkumchery Rajendrakumar                                            const MemRegion *Region,
17376c05777SNithin Vadukkumchery Rajendrakumar                                            const SVal *RegionInnerPointerVal) {
17476c05777SNithin Vadukkumchery Rajendrakumar   if (RegionInnerPointerVal) {
17576c05777SNithin Vadukkumchery Rajendrakumar     State = State->set<TrackedRegionMap>(Region, *RegionInnerPointerVal);
17676c05777SNithin Vadukkumchery Rajendrakumar   } else {
17776c05777SNithin Vadukkumchery Rajendrakumar     State = State->remove<TrackedRegionMap>(Region);
17876c05777SNithin Vadukkumchery Rajendrakumar   }
17976c05777SNithin Vadukkumchery Rajendrakumar   return State;
18076c05777SNithin Vadukkumchery Rajendrakumar }
18176c05777SNithin Vadukkumchery Rajendrakumar 
getInnerPointerType(CheckerContext C,const CXXRecordDecl * RD)18248688257SDeep Majumder static QualType getInnerPointerType(CheckerContext C, const CXXRecordDecl *RD) {
18348688257SDeep Majumder   if (!RD || !RD->isInStdNamespace())
184bc3d4d9eSNithin Vadukkumchery Rajendrakumar     return {};
185bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
18648688257SDeep Majumder   const auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD);
187bc3d4d9eSNithin Vadukkumchery Rajendrakumar   if (!TSD)
188bc3d4d9eSNithin Vadukkumchery Rajendrakumar     return {};
189bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
190bc3d4d9eSNithin Vadukkumchery Rajendrakumar   auto TemplateArgs = TSD->getTemplateArgs().asArray();
191d8253093SDeep Majumder   if (TemplateArgs.empty())
192bc3d4d9eSNithin Vadukkumchery Rajendrakumar     return {};
193bc3d4d9eSNithin Vadukkumchery Rajendrakumar   auto InnerValueType = TemplateArgs[0].getAsType();
194bc3d4d9eSNithin Vadukkumchery Rajendrakumar   return C.getASTContext().getPointerType(InnerValueType.getCanonicalType());
195bc3d4d9eSNithin Vadukkumchery Rajendrakumar }
196bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
197d8253093SDeep Majumder // This is for use with standalone-functions like std::make_unique,
198d8253093SDeep Majumder // std::make_unique_for_overwrite, etc. It reads the template parameter and
199d8253093SDeep Majumder // returns the pointer type corresponding to it,
getPointerTypeFromTemplateArg(const CallEvent & Call,CheckerContext & C)200d8253093SDeep Majumder static QualType getPointerTypeFromTemplateArg(const CallEvent &Call,
201d8253093SDeep Majumder                                               CheckerContext &C) {
202d8253093SDeep Majumder   const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
203d8253093SDeep Majumder   if (!FD || !FD->isFunctionTemplateSpecialization())
204d8253093SDeep Majumder     return {};
205d8253093SDeep Majumder   const auto &TemplateArgs = FD->getTemplateSpecializationArgs()->asArray();
206d8253093SDeep Majumder   if (TemplateArgs.size() == 0)
207d8253093SDeep Majumder     return {};
208d8253093SDeep Majumder   auto ValueType = TemplateArgs[0].getAsType();
209d8253093SDeep Majumder   return C.getASTContext().getPointerType(ValueType.getCanonicalType());
210d8253093SDeep Majumder }
211d8253093SDeep Majumder 
21248688257SDeep Majumder // Helper method to get the inner pointer type of specialized smart pointer
21348688257SDeep Majumder // Returns empty type if not found valid inner pointer type.
getInnerPointerType(const CallEvent & Call,CheckerContext & C)21448688257SDeep Majumder static QualType getInnerPointerType(const CallEvent &Call, CheckerContext &C) {
21548688257SDeep Majumder   const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
21648688257SDeep Majumder   if (!MethodDecl || !MethodDecl->getParent())
21748688257SDeep Majumder     return {};
21848688257SDeep Majumder 
21948688257SDeep Majumder   const auto *RecordDecl = MethodDecl->getParent();
22048688257SDeep Majumder   return getInnerPointerType(C, RecordDecl);
22148688257SDeep Majumder }
22248688257SDeep Majumder 
223bc3d4d9eSNithin Vadukkumchery Rajendrakumar // Helper method to pretty print region and avoid extra spacing.
checkAndPrettyPrintRegion(llvm::raw_ostream & OS,const MemRegion * Region)224bc3d4d9eSNithin Vadukkumchery Rajendrakumar static void checkAndPrettyPrintRegion(llvm::raw_ostream &OS,
225bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                       const MemRegion *Region) {
226bc3d4d9eSNithin Vadukkumchery Rajendrakumar   if (Region->canPrintPretty()) {
227bc3d4d9eSNithin Vadukkumchery Rajendrakumar     OS << " ";
228bc3d4d9eSNithin Vadukkumchery Rajendrakumar     Region->printPretty(OS);
229bc3d4d9eSNithin Vadukkumchery Rajendrakumar   }
230bc3d4d9eSNithin Vadukkumchery Rajendrakumar }
231bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
isBoolConversionMethod(const CallEvent & Call) const232bc3d4d9eSNithin Vadukkumchery Rajendrakumar bool SmartPtrModeling::isBoolConversionMethod(const CallEvent &Call) const {
2338c6119a4SArtem Dergachev   // TODO: Update CallDescription to support anonymous calls?
2348c6119a4SArtem Dergachev   // TODO: Handle other methods, such as .get() or .release().
2358c6119a4SArtem Dergachev   // But once we do, we'd need a visitor to explain null dereferences
2368c6119a4SArtem Dergachev   // that are found via such modeling.
23744820630SArtem Dergachev   const auto *CD = dyn_cast_or_null<CXXConversionDecl>(Call.getDecl());
2388c6119a4SArtem Dergachev   return CD && CD->getConversionType()->isBooleanType();
2398c6119a4SArtem Dergachev }
2408c6119a4SArtem Dergachev 
24113fe7821SDeep Majumder constexpr llvm::StringLiteral BASIC_OSTREAM_NAMES[] = {"basic_ostream"};
24213fe7821SDeep Majumder 
isStdBasicOstream(const Expr * E)24313fe7821SDeep Majumder bool isStdBasicOstream(const Expr *E) {
24413fe7821SDeep Majumder   const auto *RD = E->getType()->getAsCXXRecordDecl();
24513fe7821SDeep Majumder   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
24613fe7821SDeep Majumder }
24713fe7821SDeep Majumder 
isStdFunctionCall(const CallEvent & Call)24880068ca6SDeep Majumder static bool isStdFunctionCall(const CallEvent &Call) {
24980068ca6SDeep Majumder   return Call.getDecl() && Call.getDecl()->getDeclContext()->isStdNamespace();
25080068ca6SDeep Majumder }
25180068ca6SDeep Majumder 
isStdOstreamOperatorCall(const CallEvent & Call)25213fe7821SDeep Majumder bool isStdOstreamOperatorCall(const CallEvent &Call) {
25380068ca6SDeep Majumder   if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
25413fe7821SDeep Majumder     return false;
25513fe7821SDeep Majumder   const auto *FC = dyn_cast<SimpleFunctionCall>(&Call);
25613fe7821SDeep Majumder   if (!FC)
25713fe7821SDeep Majumder     return false;
25813fe7821SDeep Majumder   const FunctionDecl *FD = FC->getDecl();
25913fe7821SDeep Majumder   if (!FD->isOverloadedOperator())
26013fe7821SDeep Majumder     return false;
26113fe7821SDeep Majumder   const OverloadedOperatorKind OOK = FD->getOverloadedOperator();
26213fe7821SDeep Majumder   if (OOK != clang::OO_LessLess)
26313fe7821SDeep Majumder     return false;
26413fe7821SDeep Majumder   return isStdSmartPtr(Call.getArgExpr(1)) &&
26513fe7821SDeep Majumder          isStdBasicOstream(Call.getArgExpr(0));
26613fe7821SDeep Majumder }
26713fe7821SDeep Majumder 
isPotentiallyComparisionOpCall(const CallEvent & Call)26880068ca6SDeep Majumder static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
26980068ca6SDeep Majumder   if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
27080068ca6SDeep Majumder     return false;
27180068ca6SDeep Majumder   return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
27280068ca6SDeep Majumder          smartptr::isStdSmartPtr(Call.getArgExpr(1));
27380068ca6SDeep Majumder }
27480068ca6SDeep Majumder 
evalCall(const CallEvent & Call,CheckerContext & C) const27544820630SArtem Dergachev bool SmartPtrModeling::evalCall(const CallEvent &Call,
27644820630SArtem Dergachev                                 CheckerContext &C) const {
277d8253093SDeep Majumder 
27806d100a6SNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
27948688257SDeep Majumder 
28048688257SDeep Majumder   // If any one of the arg is a unique_ptr, then
28148688257SDeep Majumder   // we can try this function
28280068ca6SDeep Majumder   if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
28348688257SDeep Majumder     if (handleComparisionOp(Call, C))
28448688257SDeep Majumder       return true;
28548688257SDeep Majumder 
28680068ca6SDeep Majumder   if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
28713fe7821SDeep Majumder     return handleOstreamOperator(Call, C);
28813fe7821SDeep Majumder 
289f18da190SBalazs Benics   if (StdSwapCall.matches(Call)) {
2900cd98befSDeep Majumder     // Check the first arg, if it is of std::unique_ptr type.
2910cd98befSDeep Majumder     assert(Call.getNumArgs() == 2 && "std::swap should have two arguments");
2920cd98befSDeep Majumder     const Expr *FirstArg = Call.getArgExpr(0);
2930cd98befSDeep Majumder     if (!smartptr::isStdSmartPtr(FirstArg->getType()->getAsCXXRecordDecl()))
2940cd98befSDeep Majumder       return false;
2950cd98befSDeep Majumder     return handleSwap(State, Call.getArgSVal(0), Call.getArgSVal(1), C);
2960cd98befSDeep Majumder   }
2970cd98befSDeep Majumder 
298f18da190SBalazs Benics   if (matchesAny(Call, StdMakeUniqueCall, StdMakeUniqueForOverwriteCall)) {
299d8253093SDeep Majumder     if (!ModelSmartPtrDereference)
300d8253093SDeep Majumder       return false;
301d8253093SDeep Majumder 
302d8253093SDeep Majumder     const Optional<SVal> ThisRegionOpt = Call.getReturnValueUnderConstruction();
303d8253093SDeep Majumder     if (!ThisRegionOpt)
304d8253093SDeep Majumder       return false;
305d8253093SDeep Majumder 
306d8253093SDeep Majumder     const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal(
307d8253093SDeep Majumder         Call.getOriginExpr(), C.getLocationContext(),
308d8253093SDeep Majumder         getPointerTypeFromTemplateArg(Call, C), C.blockCount());
309d8253093SDeep Majumder 
310d8253093SDeep Majumder     const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
311d8253093SDeep Majumder     State = State->set<TrackedRegionMap>(ThisRegion, PtrVal);
312d8253093SDeep Majumder     State = State->assume(PtrVal, true);
313d8253093SDeep Majumder 
314d8253093SDeep Majumder     // TODO: ExprEngine should do this for us.
315d8253093SDeep Majumder     // For a bit more context:
316d8253093SDeep Majumder     // 1) Why do we need this? Since we are modelling a "function"
317d8253093SDeep Majumder     // that returns a constructed object we need to store this information in
318d8253093SDeep Majumder     // the program state.
319d8253093SDeep Majumder     //
320d8253093SDeep Majumder     // 2) Why does this work?
321d8253093SDeep Majumder     // `updateObjectsUnderConstruction` does exactly as it sounds.
322d8253093SDeep Majumder     //
323d8253093SDeep Majumder     // 3) How should it look like when moved to the Engine?
324d8253093SDeep Majumder     // It would be nice if we can just
325d8253093SDeep Majumder     // pretend we don't need to know about this - ie, completely automatic work.
326d8253093SDeep Majumder     // However, realistically speaking, I think we would need to "signal" the
327d8253093SDeep Majumder     // ExprEngine evalCall handler that we are constructing an object with this
328d8253093SDeep Majumder     // function call (constructors obviously construct, hence can be
329d8253093SDeep Majumder     // automatically deduced).
330d8253093SDeep Majumder     auto &Engine = State->getStateManager().getOwningEngine();
331d8253093SDeep Majumder     State = Engine.updateObjectsUnderConstruction(
332d8253093SDeep Majumder         *ThisRegionOpt, nullptr, State, C.getLocationContext(),
333d8253093SDeep Majumder         Call.getConstructionContext(), {});
334d8253093SDeep Majumder 
335d8253093SDeep Majumder     // We don't leave a note here since it is guaranteed the
336d8253093SDeep Majumder     // unique_ptr from this call is non-null (hence is safe to de-reference).
337d8253093SDeep Majumder     C.addTransition(State);
338d8253093SDeep Majumder     return true;
339d8253093SDeep Majumder   }
340d8253093SDeep Majumder 
34120e271a9SNithin Vadukkumchery Rajendrakumar   if (!smartptr::isStdSmartPtrCall(Call))
3428c6119a4SArtem Dergachev     return false;
3438c6119a4SArtem Dergachev 
344bc3d4d9eSNithin Vadukkumchery Rajendrakumar   if (isBoolConversionMethod(Call)) {
34544820630SArtem Dergachev     const MemRegion *ThisR =
34644820630SArtem Dergachev         cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
3478c6119a4SArtem Dergachev 
348bc3d4d9eSNithin Vadukkumchery Rajendrakumar     if (ModelSmartPtrDereference) {
349bc3d4d9eSNithin Vadukkumchery Rajendrakumar       // The check for the region is moved is duplicated in handleBoolOperation
350bc3d4d9eSNithin Vadukkumchery Rajendrakumar       // method.
351bc3d4d9eSNithin Vadukkumchery Rajendrakumar       // FIXME: Once we model std::move for smart pointers clean up this and use
352bc3d4d9eSNithin Vadukkumchery Rajendrakumar       // that modeling.
353bc3d4d9eSNithin Vadukkumchery Rajendrakumar       handleBoolConversion(Call, C);
354bc3d4d9eSNithin Vadukkumchery Rajendrakumar       return true;
355bc3d4d9eSNithin Vadukkumchery Rajendrakumar     } else {
3568c6119a4SArtem Dergachev       if (!move::isMovedFrom(State, ThisR)) {
35776c05777SNithin Vadukkumchery Rajendrakumar         // TODO: Model this case as well. At least, avoid invalidation of
35876c05777SNithin Vadukkumchery Rajendrakumar         // globals.
3598c6119a4SArtem Dergachev         return false;
3608c6119a4SArtem Dergachev       }
3618c6119a4SArtem Dergachev 
3628c6119a4SArtem Dergachev       // TODO: Add a note to bug reports describing this decision.
363bc3d4d9eSNithin Vadukkumchery Rajendrakumar       C.addTransition(State->BindExpr(
364bc3d4d9eSNithin Vadukkumchery Rajendrakumar           Call.getOriginExpr(), C.getLocationContext(),
36544820630SArtem Dergachev           C.getSValBuilder().makeZeroVal(Call.getResultType())));
366bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
3678c6119a4SArtem Dergachev       return true;
3688c6119a4SArtem Dergachev     }
369bc3d4d9eSNithin Vadukkumchery Rajendrakumar   }
3708c6119a4SArtem Dergachev 
37120e271a9SNithin Vadukkumchery Rajendrakumar   if (!ModelSmartPtrDereference)
37220e271a9SNithin Vadukkumchery Rajendrakumar     return false;
37320e271a9SNithin Vadukkumchery Rajendrakumar 
37420e271a9SNithin Vadukkumchery Rajendrakumar   if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
3751b743a9eSNithin Vadukkumchery Rajendrakumar     if (CC->getDecl()->isCopyConstructor())
37620e271a9SNithin Vadukkumchery Rajendrakumar       return false;
37720e271a9SNithin Vadukkumchery Rajendrakumar 
37806d100a6SNithin Vadukkumchery Rajendrakumar     const MemRegion *ThisRegion = CC->getCXXThisVal().getAsRegion();
37906d100a6SNithin Vadukkumchery Rajendrakumar     if (!ThisRegion)
38020e271a9SNithin Vadukkumchery Rajendrakumar       return false;
38120e271a9SNithin Vadukkumchery Rajendrakumar 
38298588841SVince Bridgers     QualType ThisType = cast<CXXMethodDecl>(Call.getDecl())->getThisType();
38398588841SVince Bridgers 
3841b743a9eSNithin Vadukkumchery Rajendrakumar     if (CC->getDecl()->isMoveConstructor())
3851b743a9eSNithin Vadukkumchery Rajendrakumar       return handleMoveCtr(Call, C, ThisRegion);
3861b743a9eSNithin Vadukkumchery Rajendrakumar 
38706d100a6SNithin Vadukkumchery Rajendrakumar     if (Call.getNumArgs() == 0) {
38898588841SVince Bridgers       auto NullVal = C.getSValBuilder().makeNullWithType(ThisType);
38906d100a6SNithin Vadukkumchery Rajendrakumar       State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
39006d100a6SNithin Vadukkumchery Rajendrakumar 
39106d100a6SNithin Vadukkumchery Rajendrakumar       C.addTransition(
39206d100a6SNithin Vadukkumchery Rajendrakumar           State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR,
39306d100a6SNithin Vadukkumchery Rajendrakumar                                            llvm::raw_ostream &OS) {
39406d100a6SNithin Vadukkumchery Rajendrakumar             if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
39506d100a6SNithin Vadukkumchery Rajendrakumar                 !BR.isInteresting(ThisRegion))
39606d100a6SNithin Vadukkumchery Rajendrakumar               return;
39706d100a6SNithin Vadukkumchery Rajendrakumar             OS << "Default constructed smart pointer";
398bc3d4d9eSNithin Vadukkumchery Rajendrakumar             checkAndPrettyPrintRegion(OS, ThisRegion);
39906d100a6SNithin Vadukkumchery Rajendrakumar             OS << " is null";
40006d100a6SNithin Vadukkumchery Rajendrakumar           }));
40106d100a6SNithin Vadukkumchery Rajendrakumar     } else {
40206d100a6SNithin Vadukkumchery Rajendrakumar       const auto *TrackingExpr = Call.getArgExpr(0);
40306d100a6SNithin Vadukkumchery Rajendrakumar       assert(TrackingExpr->getType()->isPointerType() &&
40406d100a6SNithin Vadukkumchery Rajendrakumar              "Adding a non pointer value to TrackedRegionMap");
40506d100a6SNithin Vadukkumchery Rajendrakumar       auto ArgVal = Call.getArgSVal(0);
40606d100a6SNithin Vadukkumchery Rajendrakumar       State = State->set<TrackedRegionMap>(ThisRegion, ArgVal);
40706d100a6SNithin Vadukkumchery Rajendrakumar 
40806d100a6SNithin Vadukkumchery Rajendrakumar       C.addTransition(State, C.getNoteTag([ThisRegion, TrackingExpr,
40906d100a6SNithin Vadukkumchery Rajendrakumar                                            ArgVal](PathSensitiveBugReport &BR,
41006d100a6SNithin Vadukkumchery Rajendrakumar                                                    llvm::raw_ostream &OS) {
41106d100a6SNithin Vadukkumchery Rajendrakumar         if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
41206d100a6SNithin Vadukkumchery Rajendrakumar             !BR.isInteresting(ThisRegion))
41306d100a6SNithin Vadukkumchery Rajendrakumar           return;
41406d100a6SNithin Vadukkumchery Rajendrakumar         bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR);
41506d100a6SNithin Vadukkumchery Rajendrakumar         OS << "Smart pointer";
416bc3d4d9eSNithin Vadukkumchery Rajendrakumar         checkAndPrettyPrintRegion(OS, ThisRegion);
41706d100a6SNithin Vadukkumchery Rajendrakumar         if (ArgVal.isZeroConstant())
41806d100a6SNithin Vadukkumchery Rajendrakumar           OS << " is constructed using a null value";
41906d100a6SNithin Vadukkumchery Rajendrakumar         else
42006d100a6SNithin Vadukkumchery Rajendrakumar           OS << " is constructed";
42106d100a6SNithin Vadukkumchery Rajendrakumar       }));
42206d100a6SNithin Vadukkumchery Rajendrakumar     }
42320e271a9SNithin Vadukkumchery Rajendrakumar     return true;
42420e271a9SNithin Vadukkumchery Rajendrakumar   }
42520e271a9SNithin Vadukkumchery Rajendrakumar 
42620676cabSNithin Vadukkumchery Rajendrakumar   if (handleAssignOp(Call, C))
42720676cabSNithin Vadukkumchery Rajendrakumar     return true;
42820676cabSNithin Vadukkumchery Rajendrakumar 
42920e271a9SNithin Vadukkumchery Rajendrakumar   const SmartPtrMethodHandlerFn *Handler = SmartPtrMethodHandlers.lookup(Call);
43020e271a9SNithin Vadukkumchery Rajendrakumar   if (!Handler)
43120e271a9SNithin Vadukkumchery Rajendrakumar     return false;
43220e271a9SNithin Vadukkumchery Rajendrakumar   (this->**Handler)(Call, C);
43320e271a9SNithin Vadukkumchery Rajendrakumar 
43420e271a9SNithin Vadukkumchery Rajendrakumar   return C.isDifferent();
43520e271a9SNithin Vadukkumchery Rajendrakumar }
43620e271a9SNithin Vadukkumchery Rajendrakumar 
retrieveOrConjureInnerPtrVal(ProgramStateRef State,const MemRegion * ThisRegion,const Expr * E,QualType Type,CheckerContext & C) const43748688257SDeep Majumder std::pair<SVal, ProgramStateRef> SmartPtrModeling::retrieveOrConjureInnerPtrVal(
43848688257SDeep Majumder     ProgramStateRef State, const MemRegion *ThisRegion, const Expr *E,
43948688257SDeep Majumder     QualType Type, CheckerContext &C) const {
44048688257SDeep Majumder   const auto *Ptr = State->get<TrackedRegionMap>(ThisRegion);
44148688257SDeep Majumder   if (Ptr)
44248688257SDeep Majumder     return {*Ptr, State};
44348688257SDeep Majumder   auto Val = C.getSValBuilder().conjureSymbolVal(E, C.getLocationContext(),
44448688257SDeep Majumder                                                  Type, C.blockCount());
44548688257SDeep Majumder   State = State->set<TrackedRegionMap>(ThisRegion, Val);
44648688257SDeep Majumder   return {Val, State};
44748688257SDeep Majumder }
44848688257SDeep Majumder 
handleComparisionOp(const CallEvent & Call,CheckerContext & C) const44948688257SDeep Majumder bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call,
45048688257SDeep Majumder                                            CheckerContext &C) const {
45148688257SDeep Majumder   const auto *FC = dyn_cast<SimpleFunctionCall>(&Call);
45248688257SDeep Majumder   if (!FC)
45348688257SDeep Majumder     return false;
45448688257SDeep Majumder   const FunctionDecl *FD = FC->getDecl();
45548688257SDeep Majumder   if (!FD->isOverloadedOperator())
45648688257SDeep Majumder     return false;
45748688257SDeep Majumder   const OverloadedOperatorKind OOK = FD->getOverloadedOperator();
45848688257SDeep Majumder   if (!(OOK == OO_EqualEqual || OOK == OO_ExclaimEqual || OOK == OO_Less ||
45948688257SDeep Majumder         OOK == OO_LessEqual || OOK == OO_Greater || OOK == OO_GreaterEqual ||
46048688257SDeep Majumder         OOK == OO_Spaceship))
46148688257SDeep Majumder     return false;
46248688257SDeep Majumder 
46348688257SDeep Majumder   // There are some special cases about which we can infer about
46448688257SDeep Majumder   // the resulting answer.
46548688257SDeep Majumder   // For reference, there is a discussion at https://reviews.llvm.org/D104616.
46648688257SDeep Majumder   // Also, the cppreference page is good to look at
46748688257SDeep Majumder   // https://en.cppreference.com/w/cpp/memory/unique_ptr/operator_cmp.
46848688257SDeep Majumder 
46948688257SDeep Majumder   auto makeSValFor = [&C, this](ProgramStateRef State, const Expr *E,
47048688257SDeep Majumder                                 SVal S) -> std::pair<SVal, ProgramStateRef> {
47148688257SDeep Majumder     if (S.isZeroConstant()) {
47248688257SDeep Majumder       return {S, State};
47348688257SDeep Majumder     }
47448688257SDeep Majumder     const MemRegion *Reg = S.getAsRegion();
47548688257SDeep Majumder     assert(Reg &&
47648688257SDeep Majumder            "this pointer of std::unique_ptr should be obtainable as MemRegion");
47748688257SDeep Majumder     QualType Type = getInnerPointerType(C, E->getType()->getAsCXXRecordDecl());
47848688257SDeep Majumder     return retrieveOrConjureInnerPtrVal(State, Reg, E, Type, C);
47948688257SDeep Majumder   };
48048688257SDeep Majumder 
48148688257SDeep Majumder   SVal First = Call.getArgSVal(0);
48248688257SDeep Majumder   SVal Second = Call.getArgSVal(1);
48348688257SDeep Majumder   const auto *FirstExpr = Call.getArgExpr(0);
48448688257SDeep Majumder   const auto *SecondExpr = Call.getArgExpr(1);
48548688257SDeep Majumder 
48648688257SDeep Majumder   const auto *ResultExpr = Call.getOriginExpr();
48748688257SDeep Majumder   const auto *LCtx = C.getLocationContext();
48848688257SDeep Majumder   auto &Bldr = C.getSValBuilder();
48948688257SDeep Majumder   ProgramStateRef State = C.getState();
49048688257SDeep Majumder 
49148688257SDeep Majumder   SVal FirstPtrVal, SecondPtrVal;
49248688257SDeep Majumder   std::tie(FirstPtrVal, State) = makeSValFor(State, FirstExpr, First);
49348688257SDeep Majumder   std::tie(SecondPtrVal, State) = makeSValFor(State, SecondExpr, Second);
49448688257SDeep Majumder   BinaryOperatorKind BOK =
49548688257SDeep Majumder       operationKindFromOverloadedOperator(OOK, true).GetBinaryOpUnsafe();
49648688257SDeep Majumder   auto RetVal = Bldr.evalBinOp(State, BOK, FirstPtrVal, SecondPtrVal,
49748688257SDeep Majumder                                Call.getResultType());
49848688257SDeep Majumder 
49948688257SDeep Majumder   if (OOK != OO_Spaceship) {
50048688257SDeep Majumder     ProgramStateRef TrueState, FalseState;
50148688257SDeep Majumder     std::tie(TrueState, FalseState) =
50248688257SDeep Majumder         State->assume(*RetVal.getAs<DefinedOrUnknownSVal>());
50348688257SDeep Majumder     if (TrueState)
50448688257SDeep Majumder       C.addTransition(
50548688257SDeep Majumder           TrueState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(true)));
50648688257SDeep Majumder     if (FalseState)
50748688257SDeep Majumder       C.addTransition(
50848688257SDeep Majumder           FalseState->BindExpr(ResultExpr, LCtx, Bldr.makeTruthVal(false)));
50948688257SDeep Majumder   } else {
51048688257SDeep Majumder     C.addTransition(State->BindExpr(ResultExpr, LCtx, RetVal));
51148688257SDeep Majumder   }
51248688257SDeep Majumder   return true;
51348688257SDeep Majumder }
51448688257SDeep Majumder 
handleOstreamOperator(const CallEvent & Call,CheckerContext & C) const51513fe7821SDeep Majumder bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call,
51613fe7821SDeep Majumder                                              CheckerContext &C) const {
51713fe7821SDeep Majumder   // operator<< does not modify the smart pointer.
51813fe7821SDeep Majumder   // And we don't really have much of modelling of basic_ostream.
51913fe7821SDeep Majumder   // So, we are better off:
52013fe7821SDeep Majumder   // 1) Invalidating the mem-region of the ostream object at hand.
52113fe7821SDeep Majumder   // 2) Setting the SVal of the basic_ostream as the return value.
52213fe7821SDeep Majumder   // Not very satisfying, but it gets the job done, and is better
52313fe7821SDeep Majumder   // than the default handling. :)
52413fe7821SDeep Majumder 
52513fe7821SDeep Majumder   ProgramStateRef State = C.getState();
52613fe7821SDeep Majumder   const auto StreamVal = Call.getArgSVal(0);
52713fe7821SDeep Majumder   const MemRegion *StreamThisRegion = StreamVal.getAsRegion();
52813fe7821SDeep Majumder   if (!StreamThisRegion)
52913fe7821SDeep Majumder     return false;
53013fe7821SDeep Majumder   State =
53113fe7821SDeep Majumder       State->invalidateRegions({StreamThisRegion}, Call.getOriginExpr(),
53213fe7821SDeep Majumder                                C.blockCount(), C.getLocationContext(), false);
53313fe7821SDeep Majumder   State =
53413fe7821SDeep Majumder       State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal);
53513fe7821SDeep Majumder   C.addTransition(State);
53613fe7821SDeep Majumder   return true;
53713fe7821SDeep Majumder }
53813fe7821SDeep Majumder 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const53920e271a9SNithin Vadukkumchery Rajendrakumar void SmartPtrModeling::checkDeadSymbols(SymbolReaper &SymReaper,
54020e271a9SNithin Vadukkumchery Rajendrakumar                                         CheckerContext &C) const {
54120e271a9SNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
54220e271a9SNithin Vadukkumchery Rajendrakumar   // Clean up dead regions from the region map.
54320e271a9SNithin Vadukkumchery Rajendrakumar   TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
54420e271a9SNithin Vadukkumchery Rajendrakumar   for (auto E : TrackedRegions) {
54520e271a9SNithin Vadukkumchery Rajendrakumar     const MemRegion *Region = E.first;
54620e271a9SNithin Vadukkumchery Rajendrakumar     bool IsRegDead = !SymReaper.isLiveRegion(Region);
54720e271a9SNithin Vadukkumchery Rajendrakumar 
54820e271a9SNithin Vadukkumchery Rajendrakumar     if (IsRegDead)
54920e271a9SNithin Vadukkumchery Rajendrakumar       State = State->remove<TrackedRegionMap>(Region);
55020e271a9SNithin Vadukkumchery Rajendrakumar   }
55120e271a9SNithin Vadukkumchery Rajendrakumar   C.addTransition(State);
55220e271a9SNithin Vadukkumchery Rajendrakumar }
55320e271a9SNithin Vadukkumchery Rajendrakumar 
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const554bc3d4d9eSNithin Vadukkumchery Rajendrakumar void SmartPtrModeling::printState(raw_ostream &Out, ProgramStateRef State,
555bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                   const char *NL, const char *Sep) const {
556bc3d4d9eSNithin Vadukkumchery Rajendrakumar   TrackedRegionMapTy RS = State->get<TrackedRegionMap>();
557bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
558bc3d4d9eSNithin Vadukkumchery Rajendrakumar   if (!RS.isEmpty()) {
559bc3d4d9eSNithin Vadukkumchery Rajendrakumar     Out << Sep << "Smart ptr regions :" << NL;
560bc3d4d9eSNithin Vadukkumchery Rajendrakumar     for (auto I : RS) {
561bc3d4d9eSNithin Vadukkumchery Rajendrakumar       I.first->dumpToStream(Out);
562bc3d4d9eSNithin Vadukkumchery Rajendrakumar       if (smartptr::isNullSmartPtr(State, I.first))
563bc3d4d9eSNithin Vadukkumchery Rajendrakumar         Out << ": Null";
564bc3d4d9eSNithin Vadukkumchery Rajendrakumar       else
565bc3d4d9eSNithin Vadukkumchery Rajendrakumar         Out << ": Non Null";
566bc3d4d9eSNithin Vadukkumchery Rajendrakumar       Out << NL;
567bc3d4d9eSNithin Vadukkumchery Rajendrakumar     }
568bc3d4d9eSNithin Vadukkumchery Rajendrakumar   }
569bc3d4d9eSNithin Vadukkumchery Rajendrakumar }
570bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
checkRegionChanges(ProgramStateRef State,const InvalidatedSymbols * Invalidated,ArrayRef<const MemRegion * > ExplicitRegions,ArrayRef<const MemRegion * > Regions,const LocationContext * LCtx,const CallEvent * Call) const571a5609102SNithin Vadukkumchery Rajendrakumar ProgramStateRef SmartPtrModeling::checkRegionChanges(
572a5609102SNithin Vadukkumchery Rajendrakumar     ProgramStateRef State, const InvalidatedSymbols *Invalidated,
573a5609102SNithin Vadukkumchery Rajendrakumar     ArrayRef<const MemRegion *> ExplicitRegions,
574a5609102SNithin Vadukkumchery Rajendrakumar     ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
575a5609102SNithin Vadukkumchery Rajendrakumar     const CallEvent *Call) const {
576a5609102SNithin Vadukkumchery Rajendrakumar   TrackedRegionMapTy RegionMap = State->get<TrackedRegionMap>();
577a5609102SNithin Vadukkumchery Rajendrakumar   TrackedRegionMapTy::Factory &RegionMapFactory =
578a5609102SNithin Vadukkumchery Rajendrakumar       State->get_context<TrackedRegionMap>();
579a5609102SNithin Vadukkumchery Rajendrakumar   for (const auto *Region : Regions)
580a5609102SNithin Vadukkumchery Rajendrakumar     RegionMap = removeTrackedSubregions(RegionMap, RegionMapFactory,
581a5609102SNithin Vadukkumchery Rajendrakumar                                         Region->getBaseRegion());
582a5609102SNithin Vadukkumchery Rajendrakumar   return State->set<TrackedRegionMap>(RegionMap);
583a5609102SNithin Vadukkumchery Rajendrakumar }
584a5609102SNithin Vadukkumchery Rajendrakumar 
checkLiveSymbols(ProgramStateRef State,SymbolReaper & SR) const585bc3d4d9eSNithin Vadukkumchery Rajendrakumar void SmartPtrModeling::checkLiveSymbols(ProgramStateRef State,
586bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                         SymbolReaper &SR) const {
587bc3d4d9eSNithin Vadukkumchery Rajendrakumar   // Marking tracked symbols alive
588bc3d4d9eSNithin Vadukkumchery Rajendrakumar   TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
589bc3d4d9eSNithin Vadukkumchery Rajendrakumar   for (auto I = TrackedRegions.begin(), E = TrackedRegions.end(); I != E; ++I) {
590bc3d4d9eSNithin Vadukkumchery Rajendrakumar     SVal Val = I->second;
591bc3d4d9eSNithin Vadukkumchery Rajendrakumar     for (auto si = Val.symbol_begin(), se = Val.symbol_end(); si != se; ++si) {
592bc3d4d9eSNithin Vadukkumchery Rajendrakumar       SR.markLive(*si);
593bc3d4d9eSNithin Vadukkumchery Rajendrakumar     }
594bc3d4d9eSNithin Vadukkumchery Rajendrakumar   }
595bc3d4d9eSNithin Vadukkumchery Rajendrakumar }
596bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
handleReset(const CallEvent & Call,CheckerContext & C) const59720e271a9SNithin Vadukkumchery Rajendrakumar void SmartPtrModeling::handleReset(const CallEvent &Call,
59820e271a9SNithin Vadukkumchery Rajendrakumar                                    CheckerContext &C) const {
59906d100a6SNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
60020e271a9SNithin Vadukkumchery Rajendrakumar   const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
60120e271a9SNithin Vadukkumchery Rajendrakumar   if (!IC)
60220e271a9SNithin Vadukkumchery Rajendrakumar     return;
60320e271a9SNithin Vadukkumchery Rajendrakumar 
60406d100a6SNithin Vadukkumchery Rajendrakumar   const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
60506d100a6SNithin Vadukkumchery Rajendrakumar   if (!ThisRegion)
60620e271a9SNithin Vadukkumchery Rajendrakumar     return;
60706d100a6SNithin Vadukkumchery Rajendrakumar 
60806d100a6SNithin Vadukkumchery Rajendrakumar   assert(Call.getArgExpr(0)->getType()->isPointerType() &&
60906d100a6SNithin Vadukkumchery Rajendrakumar          "Adding a non pointer value to TrackedRegionMap");
61006d100a6SNithin Vadukkumchery Rajendrakumar   State = State->set<TrackedRegionMap>(ThisRegion, Call.getArgSVal(0));
61106d100a6SNithin Vadukkumchery Rajendrakumar   const auto *TrackingExpr = Call.getArgExpr(0);
61206d100a6SNithin Vadukkumchery Rajendrakumar   C.addTransition(
61306d100a6SNithin Vadukkumchery Rajendrakumar       State, C.getNoteTag([ThisRegion, TrackingExpr](PathSensitiveBugReport &BR,
61406d100a6SNithin Vadukkumchery Rajendrakumar                                                      llvm::raw_ostream &OS) {
61506d100a6SNithin Vadukkumchery Rajendrakumar         if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
61606d100a6SNithin Vadukkumchery Rajendrakumar             !BR.isInteresting(ThisRegion))
61706d100a6SNithin Vadukkumchery Rajendrakumar           return;
61806d100a6SNithin Vadukkumchery Rajendrakumar         bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR);
61906d100a6SNithin Vadukkumchery Rajendrakumar         OS << "Smart pointer";
620bc3d4d9eSNithin Vadukkumchery Rajendrakumar         checkAndPrettyPrintRegion(OS, ThisRegion);
62106d100a6SNithin Vadukkumchery Rajendrakumar         OS << " reset using a null value";
62206d100a6SNithin Vadukkumchery Rajendrakumar       }));
62376c05777SNithin Vadukkumchery Rajendrakumar   // TODO: Make sure to ivalidate the region in the Store if we don't have
62420e271a9SNithin Vadukkumchery Rajendrakumar   // time to model all methods.
62520e271a9SNithin Vadukkumchery Rajendrakumar }
62620e271a9SNithin Vadukkumchery Rajendrakumar 
handleRelease(const CallEvent & Call,CheckerContext & C) const62720e271a9SNithin Vadukkumchery Rajendrakumar void SmartPtrModeling::handleRelease(const CallEvent &Call,
62820e271a9SNithin Vadukkumchery Rajendrakumar                                      CheckerContext &C) const {
62906d100a6SNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
63020e271a9SNithin Vadukkumchery Rajendrakumar   const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
63120e271a9SNithin Vadukkumchery Rajendrakumar   if (!IC)
63220e271a9SNithin Vadukkumchery Rajendrakumar     return;
63320e271a9SNithin Vadukkumchery Rajendrakumar 
63406d100a6SNithin Vadukkumchery Rajendrakumar   const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
63506d100a6SNithin Vadukkumchery Rajendrakumar   if (!ThisRegion)
63620e271a9SNithin Vadukkumchery Rajendrakumar     return;
63720e271a9SNithin Vadukkumchery Rajendrakumar 
63806d100a6SNithin Vadukkumchery Rajendrakumar   const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
63920e271a9SNithin Vadukkumchery Rajendrakumar 
64020e271a9SNithin Vadukkumchery Rajendrakumar   if (InnerPointVal) {
64120e271a9SNithin Vadukkumchery Rajendrakumar     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
64220e271a9SNithin Vadukkumchery Rajendrakumar                             *InnerPointVal);
64320e271a9SNithin Vadukkumchery Rajendrakumar   }
64406d100a6SNithin Vadukkumchery Rajendrakumar 
64598588841SVince Bridgers   QualType ThisType = cast<CXXMethodDecl>(Call.getDecl())->getThisType();
64698588841SVince Bridgers   auto ValueToUpdate = C.getSValBuilder().makeNullWithType(ThisType);
64706d100a6SNithin Vadukkumchery Rajendrakumar   State = State->set<TrackedRegionMap>(ThisRegion, ValueToUpdate);
64806d100a6SNithin Vadukkumchery Rajendrakumar 
64906d100a6SNithin Vadukkumchery Rajendrakumar   C.addTransition(State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR,
65006d100a6SNithin Vadukkumchery Rajendrakumar                                                    llvm::raw_ostream &OS) {
65106d100a6SNithin Vadukkumchery Rajendrakumar     if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
65206d100a6SNithin Vadukkumchery Rajendrakumar         !BR.isInteresting(ThisRegion))
65306d100a6SNithin Vadukkumchery Rajendrakumar       return;
65406d100a6SNithin Vadukkumchery Rajendrakumar 
65506d100a6SNithin Vadukkumchery Rajendrakumar     OS << "Smart pointer";
656bc3d4d9eSNithin Vadukkumchery Rajendrakumar     checkAndPrettyPrintRegion(OS, ThisRegion);
65706d100a6SNithin Vadukkumchery Rajendrakumar     OS << " is released and set to null";
65806d100a6SNithin Vadukkumchery Rajendrakumar   }));
65920e271a9SNithin Vadukkumchery Rajendrakumar   // TODO: Add support to enable MallocChecker to start tracking the raw
66020e271a9SNithin Vadukkumchery Rajendrakumar   // pointer.
66120e271a9SNithin Vadukkumchery Rajendrakumar }
66220e271a9SNithin Vadukkumchery Rajendrakumar 
handleSwapMethod(const CallEvent & Call,CheckerContext & C) const6630cd98befSDeep Majumder void SmartPtrModeling::handleSwapMethod(const CallEvent &Call,
66420e271a9SNithin Vadukkumchery Rajendrakumar                                         CheckerContext &C) const {
66576c05777SNithin Vadukkumchery Rajendrakumar   // To model unique_ptr::swap() method.
66676c05777SNithin Vadukkumchery Rajendrakumar   const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
66776c05777SNithin Vadukkumchery Rajendrakumar   if (!IC)
66876c05777SNithin Vadukkumchery Rajendrakumar     return;
66976c05777SNithin Vadukkumchery Rajendrakumar 
67076c05777SNithin Vadukkumchery Rajendrakumar   auto State = C.getState();
6710cd98befSDeep Majumder   handleSwap(State, IC->getCXXThisVal(), Call.getArgSVal(0), C);
6720cd98befSDeep Majumder }
67376c05777SNithin Vadukkumchery Rajendrakumar 
handleSwap(ProgramStateRef State,SVal First,SVal Second,CheckerContext & C) const6740cd98befSDeep Majumder bool SmartPtrModeling::handleSwap(ProgramStateRef State, SVal First,
6750cd98befSDeep Majumder                                   SVal Second, CheckerContext &C) const {
6760cd98befSDeep Majumder   const MemRegion *FirstThisRegion = First.getAsRegion();
6770cd98befSDeep Majumder   if (!FirstThisRegion)
6780cd98befSDeep Majumder     return false;
6790cd98befSDeep Majumder   const MemRegion *SecondThisRegion = Second.getAsRegion();
6800cd98befSDeep Majumder   if (!SecondThisRegion)
6810cd98befSDeep Majumder     return false;
68276c05777SNithin Vadukkumchery Rajendrakumar 
6830cd98befSDeep Majumder   const auto *FirstInnerPtrVal = State->get<TrackedRegionMap>(FirstThisRegion);
6840cd98befSDeep Majumder   const auto *SecondInnerPtrVal =
6850cd98befSDeep Majumder       State->get<TrackedRegionMap>(SecondThisRegion);
6860cd98befSDeep Majumder 
6870cd98befSDeep Majumder   State = updateSwappedRegion(State, FirstThisRegion, SecondInnerPtrVal);
6880cd98befSDeep Majumder   State = updateSwappedRegion(State, SecondThisRegion, FirstInnerPtrVal);
6890cd98befSDeep Majumder 
6900cd98befSDeep Majumder   C.addTransition(State, C.getNoteTag([FirstThisRegion, SecondThisRegion](
6910cd98befSDeep Majumder                                           PathSensitiveBugReport &BR,
69206d100a6SNithin Vadukkumchery Rajendrakumar                                           llvm::raw_ostream &OS) {
6930cd98befSDeep Majumder     if (&BR.getBugType() != smartptr::getNullDereferenceBugType())
69406d100a6SNithin Vadukkumchery Rajendrakumar       return;
6950cd98befSDeep Majumder     if (BR.isInteresting(FirstThisRegion) &&
6960cd98befSDeep Majumder         !BR.isInteresting(SecondThisRegion)) {
6970cd98befSDeep Majumder       BR.markInteresting(SecondThisRegion);
6980cd98befSDeep Majumder       BR.markNotInteresting(FirstThisRegion);
6990cd98befSDeep Majumder     }
7000cd98befSDeep Majumder     if (BR.isInteresting(SecondThisRegion) &&
7010cd98befSDeep Majumder         !BR.isInteresting(FirstThisRegion)) {
7020cd98befSDeep Majumder       BR.markInteresting(FirstThisRegion);
7030cd98befSDeep Majumder       BR.markNotInteresting(SecondThisRegion);
7040cd98befSDeep Majumder     }
7050cd98befSDeep Majumder     // TODO: We need to emit some note here probably!!
70606d100a6SNithin Vadukkumchery Rajendrakumar   }));
7070cd98befSDeep Majumder 
7080cd98befSDeep Majumder   return true;
70920e271a9SNithin Vadukkumchery Rajendrakumar }
71020e271a9SNithin Vadukkumchery Rajendrakumar 
handleGet(const CallEvent & Call,CheckerContext & C) const71155208f5aSNithin Vadukkumchery Rajendrakumar void SmartPtrModeling::handleGet(const CallEvent &Call,
71255208f5aSNithin Vadukkumchery Rajendrakumar                                  CheckerContext &C) const {
71355208f5aSNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
71455208f5aSNithin Vadukkumchery Rajendrakumar   const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
71555208f5aSNithin Vadukkumchery Rajendrakumar   if (!IC)
71655208f5aSNithin Vadukkumchery Rajendrakumar     return;
71755208f5aSNithin Vadukkumchery Rajendrakumar 
71855208f5aSNithin Vadukkumchery Rajendrakumar   const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
71955208f5aSNithin Vadukkumchery Rajendrakumar   if (!ThisRegion)
72055208f5aSNithin Vadukkumchery Rajendrakumar     return;
72155208f5aSNithin Vadukkumchery Rajendrakumar 
72255208f5aSNithin Vadukkumchery Rajendrakumar   SVal InnerPointerVal;
72348688257SDeep Majumder   std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal(
72448688257SDeep Majumder       State, ThisRegion, Call.getOriginExpr(), Call.getResultType(), C);
72555208f5aSNithin Vadukkumchery Rajendrakumar   State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
72655208f5aSNithin Vadukkumchery Rajendrakumar                           InnerPointerVal);
72755208f5aSNithin Vadukkumchery Rajendrakumar   // TODO: Add NoteTag, for how the raw pointer got using 'get' method.
72855208f5aSNithin Vadukkumchery Rajendrakumar   C.addTransition(State);
72955208f5aSNithin Vadukkumchery Rajendrakumar }
73055208f5aSNithin Vadukkumchery Rajendrakumar 
handleAssignOp(const CallEvent & Call,CheckerContext & C) const73120676cabSNithin Vadukkumchery Rajendrakumar bool SmartPtrModeling::handleAssignOp(const CallEvent &Call,
73220676cabSNithin Vadukkumchery Rajendrakumar                                       CheckerContext &C) const {
73320676cabSNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
73420676cabSNithin Vadukkumchery Rajendrakumar   const auto *OC = dyn_cast<CXXMemberOperatorCall>(&Call);
73520676cabSNithin Vadukkumchery Rajendrakumar   if (!OC)
73620676cabSNithin Vadukkumchery Rajendrakumar     return false;
73720676cabSNithin Vadukkumchery Rajendrakumar   OverloadedOperatorKind OOK = OC->getOverloadedOperator();
73820676cabSNithin Vadukkumchery Rajendrakumar   if (OOK != OO_Equal)
73920676cabSNithin Vadukkumchery Rajendrakumar     return false;
74020676cabSNithin Vadukkumchery Rajendrakumar   const MemRegion *ThisRegion = OC->getCXXThisVal().getAsRegion();
74120676cabSNithin Vadukkumchery Rajendrakumar   if (!ThisRegion)
74220676cabSNithin Vadukkumchery Rajendrakumar     return false;
74320676cabSNithin Vadukkumchery Rajendrakumar 
74498588841SVince Bridgers   QualType ThisType = cast<CXXMethodDecl>(Call.getDecl())->getThisType();
74598588841SVince Bridgers 
74620676cabSNithin Vadukkumchery Rajendrakumar   const MemRegion *OtherSmartPtrRegion = OC->getArgSVal(0).getAsRegion();
74720676cabSNithin Vadukkumchery Rajendrakumar   // In case of 'nullptr' or '0' assigned
74820676cabSNithin Vadukkumchery Rajendrakumar   if (!OtherSmartPtrRegion) {
74920676cabSNithin Vadukkumchery Rajendrakumar     bool AssignedNull = Call.getArgSVal(0).isZeroConstant();
75020676cabSNithin Vadukkumchery Rajendrakumar     if (!AssignedNull)
75120676cabSNithin Vadukkumchery Rajendrakumar       return false;
75298588841SVince Bridgers     auto NullVal = C.getSValBuilder().makeNullWithType(ThisType);
75320676cabSNithin Vadukkumchery Rajendrakumar     State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
75420676cabSNithin Vadukkumchery Rajendrakumar     C.addTransition(State, C.getNoteTag([ThisRegion](PathSensitiveBugReport &BR,
75520676cabSNithin Vadukkumchery Rajendrakumar                                                      llvm::raw_ostream &OS) {
75620676cabSNithin Vadukkumchery Rajendrakumar       if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
75720676cabSNithin Vadukkumchery Rajendrakumar           !BR.isInteresting(ThisRegion))
75820676cabSNithin Vadukkumchery Rajendrakumar         return;
75920676cabSNithin Vadukkumchery Rajendrakumar       OS << "Smart pointer";
760bc3d4d9eSNithin Vadukkumchery Rajendrakumar       checkAndPrettyPrintRegion(OS, ThisRegion);
76120676cabSNithin Vadukkumchery Rajendrakumar       OS << " is assigned to null";
76220676cabSNithin Vadukkumchery Rajendrakumar     }));
76320676cabSNithin Vadukkumchery Rajendrakumar     return true;
76420676cabSNithin Vadukkumchery Rajendrakumar   }
76520676cabSNithin Vadukkumchery Rajendrakumar 
76698588841SVince Bridgers   return updateMovedSmartPointers(C, ThisRegion, OtherSmartPtrRegion, Call);
7671b743a9eSNithin Vadukkumchery Rajendrakumar }
7681b743a9eSNithin Vadukkumchery Rajendrakumar 
handleMoveCtr(const CallEvent & Call,CheckerContext & C,const MemRegion * ThisRegion) const7691b743a9eSNithin Vadukkumchery Rajendrakumar bool SmartPtrModeling::handleMoveCtr(const CallEvent &Call, CheckerContext &C,
7701b743a9eSNithin Vadukkumchery Rajendrakumar                                      const MemRegion *ThisRegion) const {
7711b743a9eSNithin Vadukkumchery Rajendrakumar   const auto *OtherSmartPtrRegion = Call.getArgSVal(0).getAsRegion();
7721b743a9eSNithin Vadukkumchery Rajendrakumar   if (!OtherSmartPtrRegion)
7731b743a9eSNithin Vadukkumchery Rajendrakumar     return false;
7741b743a9eSNithin Vadukkumchery Rajendrakumar 
77598588841SVince Bridgers   return updateMovedSmartPointers(C, ThisRegion, OtherSmartPtrRegion, Call);
7761b743a9eSNithin Vadukkumchery Rajendrakumar }
7771b743a9eSNithin Vadukkumchery Rajendrakumar 
updateMovedSmartPointers(CheckerContext & C,const MemRegion * ThisRegion,const MemRegion * OtherSmartPtrRegion,const CallEvent & Call) const7781b743a9eSNithin Vadukkumchery Rajendrakumar bool SmartPtrModeling::updateMovedSmartPointers(
7791b743a9eSNithin Vadukkumchery Rajendrakumar     CheckerContext &C, const MemRegion *ThisRegion,
78098588841SVince Bridgers     const MemRegion *OtherSmartPtrRegion, const CallEvent &Call) const {
7811b743a9eSNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
78298588841SVince Bridgers   QualType ThisType = cast<CXXMethodDecl>(Call.getDecl())->getThisType();
78320676cabSNithin Vadukkumchery Rajendrakumar   const auto *OtherInnerPtr = State->get<TrackedRegionMap>(OtherSmartPtrRegion);
78420676cabSNithin Vadukkumchery Rajendrakumar   if (OtherInnerPtr) {
78520676cabSNithin Vadukkumchery Rajendrakumar     State = State->set<TrackedRegionMap>(ThisRegion, *OtherInnerPtr);
78698588841SVince Bridgers 
78798588841SVince Bridgers     auto NullVal = C.getSValBuilder().makeNullWithType(ThisType);
78820676cabSNithin Vadukkumchery Rajendrakumar     State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
78920676cabSNithin Vadukkumchery Rajendrakumar     bool IsArgValNull = OtherInnerPtr->isZeroConstant();
79020676cabSNithin Vadukkumchery Rajendrakumar 
79120676cabSNithin Vadukkumchery Rajendrakumar     C.addTransition(
79220676cabSNithin Vadukkumchery Rajendrakumar         State,
79320676cabSNithin Vadukkumchery Rajendrakumar         C.getNoteTag([ThisRegion, OtherSmartPtrRegion, IsArgValNull](
79420676cabSNithin Vadukkumchery Rajendrakumar                          PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
79520676cabSNithin Vadukkumchery Rajendrakumar           if (&BR.getBugType() != smartptr::getNullDereferenceBugType())
79620676cabSNithin Vadukkumchery Rajendrakumar             return;
79720676cabSNithin Vadukkumchery Rajendrakumar           if (BR.isInteresting(OtherSmartPtrRegion)) {
79820676cabSNithin Vadukkumchery Rajendrakumar             OS << "Smart pointer";
799bc3d4d9eSNithin Vadukkumchery Rajendrakumar             checkAndPrettyPrintRegion(OS, OtherSmartPtrRegion);
80020676cabSNithin Vadukkumchery Rajendrakumar             OS << " is null after being moved to";
801bc3d4d9eSNithin Vadukkumchery Rajendrakumar             checkAndPrettyPrintRegion(OS, ThisRegion);
80220676cabSNithin Vadukkumchery Rajendrakumar           }
80320676cabSNithin Vadukkumchery Rajendrakumar           if (BR.isInteresting(ThisRegion) && IsArgValNull) {
8041b743a9eSNithin Vadukkumchery Rajendrakumar             OS << "A null pointer value is moved to";
805bc3d4d9eSNithin Vadukkumchery Rajendrakumar             checkAndPrettyPrintRegion(OS, ThisRegion);
80620676cabSNithin Vadukkumchery Rajendrakumar             BR.markInteresting(OtherSmartPtrRegion);
80720676cabSNithin Vadukkumchery Rajendrakumar           }
80820676cabSNithin Vadukkumchery Rajendrakumar         }));
80920676cabSNithin Vadukkumchery Rajendrakumar     return true;
81020676cabSNithin Vadukkumchery Rajendrakumar   } else {
81120676cabSNithin Vadukkumchery Rajendrakumar     // In case we dont know anything about value we are moving from
81220676cabSNithin Vadukkumchery Rajendrakumar     // remove the entry from map for which smart pointer got moved to.
81398588841SVince Bridgers     // For unique_ptr<A>, Ty will be 'A*'.
81498588841SVince Bridgers     auto NullVal = C.getSValBuilder().makeNullWithType(ThisType);
81520676cabSNithin Vadukkumchery Rajendrakumar     State = State->remove<TrackedRegionMap>(ThisRegion);
81620676cabSNithin Vadukkumchery Rajendrakumar     State = State->set<TrackedRegionMap>(OtherSmartPtrRegion, NullVal);
81720676cabSNithin Vadukkumchery Rajendrakumar     C.addTransition(State, C.getNoteTag([OtherSmartPtrRegion,
81820676cabSNithin Vadukkumchery Rajendrakumar                                          ThisRegion](PathSensitiveBugReport &BR,
81920676cabSNithin Vadukkumchery Rajendrakumar                                                      llvm::raw_ostream &OS) {
82020676cabSNithin Vadukkumchery Rajendrakumar       if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
82120676cabSNithin Vadukkumchery Rajendrakumar           !BR.isInteresting(OtherSmartPtrRegion))
82220676cabSNithin Vadukkumchery Rajendrakumar         return;
82320676cabSNithin Vadukkumchery Rajendrakumar       OS << "Smart pointer";
824bc3d4d9eSNithin Vadukkumchery Rajendrakumar       checkAndPrettyPrintRegion(OS, OtherSmartPtrRegion);
82520676cabSNithin Vadukkumchery Rajendrakumar       OS << " is null after; previous value moved to";
826bc3d4d9eSNithin Vadukkumchery Rajendrakumar       checkAndPrettyPrintRegion(OS, ThisRegion);
82720676cabSNithin Vadukkumchery Rajendrakumar     }));
82820676cabSNithin Vadukkumchery Rajendrakumar     return true;
82920676cabSNithin Vadukkumchery Rajendrakumar   }
83020676cabSNithin Vadukkumchery Rajendrakumar   return false;
83120676cabSNithin Vadukkumchery Rajendrakumar }
83220676cabSNithin Vadukkumchery Rajendrakumar 
handleBoolConversion(const CallEvent & Call,CheckerContext & C) const833bc3d4d9eSNithin Vadukkumchery Rajendrakumar void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
834bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                             CheckerContext &C) const {
835bc3d4d9eSNithin Vadukkumchery Rajendrakumar   // To model unique_ptr::operator bool
836bc3d4d9eSNithin Vadukkumchery Rajendrakumar   ProgramStateRef State = C.getState();
837bc3d4d9eSNithin Vadukkumchery Rajendrakumar   const Expr *CallExpr = Call.getOriginExpr();
838bc3d4d9eSNithin Vadukkumchery Rajendrakumar   const MemRegion *ThisRegion =
839bc3d4d9eSNithin Vadukkumchery Rajendrakumar       cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
840bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
84198588841SVince Bridgers   QualType ThisType = cast<CXXMethodDecl>(Call.getDecl())->getThisType();
84298588841SVince Bridgers 
843bc3d4d9eSNithin Vadukkumchery Rajendrakumar   SVal InnerPointerVal;
844bc3d4d9eSNithin Vadukkumchery Rajendrakumar   if (const auto *InnerValPtr = State->get<TrackedRegionMap>(ThisRegion)) {
845bc3d4d9eSNithin Vadukkumchery Rajendrakumar     InnerPointerVal = *InnerValPtr;
846bc3d4d9eSNithin Vadukkumchery Rajendrakumar   } else {
847bc3d4d9eSNithin Vadukkumchery Rajendrakumar     // In case of inner pointer SVal is not available we create
848bc3d4d9eSNithin Vadukkumchery Rajendrakumar     // conjureSymbolVal for inner pointer value.
849bc3d4d9eSNithin Vadukkumchery Rajendrakumar     auto InnerPointerType = getInnerPointerType(Call, C);
850bc3d4d9eSNithin Vadukkumchery Rajendrakumar     if (InnerPointerType.isNull())
851bc3d4d9eSNithin Vadukkumchery Rajendrakumar       return;
852bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
853bc3d4d9eSNithin Vadukkumchery Rajendrakumar     const LocationContext *LC = C.getLocationContext();
854bc3d4d9eSNithin Vadukkumchery Rajendrakumar     InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
855bc3d4d9eSNithin Vadukkumchery Rajendrakumar         CallExpr, LC, InnerPointerType, C.blockCount());
856bc3d4d9eSNithin Vadukkumchery Rajendrakumar     State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal);
857bc3d4d9eSNithin Vadukkumchery Rajendrakumar   }
858bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
859bc3d4d9eSNithin Vadukkumchery Rajendrakumar   if (State->isNull(InnerPointerVal).isConstrainedTrue()) {
860bc3d4d9eSNithin Vadukkumchery Rajendrakumar     State = State->BindExpr(CallExpr, C.getLocationContext(),
861bc3d4d9eSNithin Vadukkumchery Rajendrakumar                             C.getSValBuilder().makeTruthVal(false));
862bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
863bc3d4d9eSNithin Vadukkumchery Rajendrakumar     C.addTransition(State);
864bc3d4d9eSNithin Vadukkumchery Rajendrakumar     return;
865bc3d4d9eSNithin Vadukkumchery Rajendrakumar   } else if (State->isNonNull(InnerPointerVal).isConstrainedTrue()) {
866bc3d4d9eSNithin Vadukkumchery Rajendrakumar     State = State->BindExpr(CallExpr, C.getLocationContext(),
867bc3d4d9eSNithin Vadukkumchery Rajendrakumar                             C.getSValBuilder().makeTruthVal(true));
868bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
869bc3d4d9eSNithin Vadukkumchery Rajendrakumar     C.addTransition(State);
870bc3d4d9eSNithin Vadukkumchery Rajendrakumar     return;
871bc3d4d9eSNithin Vadukkumchery Rajendrakumar   } else if (move::isMovedFrom(State, ThisRegion)) {
872bc3d4d9eSNithin Vadukkumchery Rajendrakumar     C.addTransition(
873bc3d4d9eSNithin Vadukkumchery Rajendrakumar         State->BindExpr(CallExpr, C.getLocationContext(),
874bc3d4d9eSNithin Vadukkumchery Rajendrakumar                         C.getSValBuilder().makeZeroVal(Call.getResultType())));
875bc3d4d9eSNithin Vadukkumchery Rajendrakumar     return;
876bc3d4d9eSNithin Vadukkumchery Rajendrakumar   } else {
877bc3d4d9eSNithin Vadukkumchery Rajendrakumar     ProgramStateRef NotNullState, NullState;
878bc3d4d9eSNithin Vadukkumchery Rajendrakumar     std::tie(NotNullState, NullState) =
879bc3d4d9eSNithin Vadukkumchery Rajendrakumar         State->assume(InnerPointerVal.castAs<DefinedOrUnknownSVal>());
880bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
88198588841SVince Bridgers     auto NullVal = C.getSValBuilder().makeNullWithType(ThisType);
882bc3d4d9eSNithin Vadukkumchery Rajendrakumar     // Explicitly tracking the region as null.
883bc3d4d9eSNithin Vadukkumchery Rajendrakumar     NullState = NullState->set<TrackedRegionMap>(ThisRegion, NullVal);
884bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
885bc3d4d9eSNithin Vadukkumchery Rajendrakumar     NullState = NullState->BindExpr(CallExpr, C.getLocationContext(),
886bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                     C.getSValBuilder().makeTruthVal(false));
887bc3d4d9eSNithin Vadukkumchery Rajendrakumar     C.addTransition(NullState, C.getNoteTag(
888bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                    [ThisRegion](PathSensitiveBugReport &BR,
889bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                                 llvm::raw_ostream &OS) {
890bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                      OS << "Assuming smart pointer";
891bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                      checkAndPrettyPrintRegion(OS, ThisRegion);
892bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                      OS << " is null";
893bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                    },
894bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                    /*IsPrunable=*/true));
895bc3d4d9eSNithin Vadukkumchery Rajendrakumar     NotNullState =
896bc3d4d9eSNithin Vadukkumchery Rajendrakumar         NotNullState->BindExpr(CallExpr, C.getLocationContext(),
897bc3d4d9eSNithin Vadukkumchery Rajendrakumar                                C.getSValBuilder().makeTruthVal(true));
898bc3d4d9eSNithin Vadukkumchery Rajendrakumar     C.addTransition(
899bc3d4d9eSNithin Vadukkumchery Rajendrakumar         NotNullState,
900bc3d4d9eSNithin Vadukkumchery Rajendrakumar         C.getNoteTag(
901bc3d4d9eSNithin Vadukkumchery Rajendrakumar             [ThisRegion](PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
902bc3d4d9eSNithin Vadukkumchery Rajendrakumar               OS << "Assuming smart pointer";
903bc3d4d9eSNithin Vadukkumchery Rajendrakumar               checkAndPrettyPrintRegion(OS, ThisRegion);
904bc3d4d9eSNithin Vadukkumchery Rajendrakumar               OS << " is non-null";
905bc3d4d9eSNithin Vadukkumchery Rajendrakumar             },
906bc3d4d9eSNithin Vadukkumchery Rajendrakumar             /*IsPrunable=*/true));
907bc3d4d9eSNithin Vadukkumchery Rajendrakumar     return;
908bc3d4d9eSNithin Vadukkumchery Rajendrakumar   }
909bc3d4d9eSNithin Vadukkumchery Rajendrakumar }
910bc3d4d9eSNithin Vadukkumchery Rajendrakumar 
registerSmartPtrModeling(CheckerManager & Mgr)9118c6119a4SArtem Dergachev void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
91220e271a9SNithin Vadukkumchery Rajendrakumar   auto *Checker = Mgr.registerChecker<SmartPtrModeling>();
91320e271a9SNithin Vadukkumchery Rajendrakumar   Checker->ModelSmartPtrDereference =
91420e271a9SNithin Vadukkumchery Rajendrakumar       Mgr.getAnalyzerOptions().getCheckerBooleanOption(
91520e271a9SNithin Vadukkumchery Rajendrakumar           Checker, "ModelSmartPtrDereference");
9168c6119a4SArtem Dergachev }
9178c6119a4SArtem Dergachev 
shouldRegisterSmartPtrModeling(const CheckerManager & mgr)918bda3dd0dSKirstóf Umann bool ento::shouldRegisterSmartPtrModeling(const CheckerManager &mgr) {
919bda3dd0dSKirstóf Umann   const LangOptions &LO = mgr.getLangOpts();
9208c6119a4SArtem Dergachev   return LO.CPlusPlus;
9218c6119a4SArtem Dergachev }
922