diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -35,9 +35,15 @@ using namespace ento; namespace { + +enum class MakeUniqueKind { + Regular, // ie, std::make_unique + ForOverwrite, // ie, std::make_unique_for_overwrite +}; + class SmartPtrModeling : public Checker { + check::LiveSymbols, check::Bind> { bool isBoolConversionMethod(const CallEvent &Call) const; @@ -56,6 +62,7 @@ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; + void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const; private: void handleReset(const CallEvent &Call, CheckerContext &C) const; @@ -76,10 +83,27 @@ {{"release"}, &SmartPtrModeling::handleRelease}, {{"swap", 1}, &SmartPtrModeling::handleSwap}, {{"get"}, &SmartPtrModeling::handleGet}}; + const CallDescription StdMakeUniqueCall{{"std", "make_unique"}}; + const CallDescription StdMakeUniqueForOverwriteCall{ + {"std", "make_unique_for_overwrite"}}; }; } // end of anonymous namespace +class MakeUniqueKindWrapper { + const MakeUniqueKind Kind; + +public: + MakeUniqueKindWrapper(MakeUniqueKind Kind) : Kind(Kind) {} + MakeUniqueKind get() const { return Kind; } + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(static_cast(Kind)); + } + bool operator==(const MakeUniqueKind &RHS) const { return Kind == RHS; } + bool operator!=(const MakeUniqueKind &RHS) const { return Kind != RHS; } +}; + REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, SVal) +REGISTER_LIST_WITH_PROGRAMSTATE(MakeUniqueKindList, MakeUniqueKindWrapper) // Define the inter-checker API. namespace clang { @@ -177,7 +201,21 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); + + if (Call.isCalled(StdMakeUniqueCall)) { + State = State->add(MakeUniqueKind::Regular); + C.addTransition(State); + return true; + } + + if (Call.isCalled(StdMakeUniqueForOverwriteCall)) { + State = State->add(MakeUniqueKind::ForOverwrite); + C.addTransition(State); + return true; + } + if (!smartptr::isStdSmartPtrCall(Call)) return false; @@ -272,6 +310,46 @@ return C.isDifferent(); } +bool isUniquePtrType(QualType QT) { + if (QT.isNull()) + return false; + const auto *Decl = QT->getAsCXXRecordDecl(); + if (!Decl || !Decl->getDeclContext()->isStdNamespace()) + return false; + const IdentifierInfo *ID = Decl->getIdentifier(); + if (!ID) + return false; + const StringRef Name = ID->getName(); + return Name == "unique_ptr"; +} + +void SmartPtrModeling::checkBind(SVal L, SVal V, const Stmt *S, + CheckerContext &C) const { + const auto *TVR = dyn_cast_or_null(L.getAsRegion()); + if (!TVR) + return; + if (!isUniquePtrType(TVR->getValueType())) + return; + const auto *ThisRegion = dyn_cast(TVR); + if (!ThisRegion) + return; + + ProgramStateRef State = C.getState(); + auto KindList = State->get(); + assert(!KindList.isEmpty() && + "Expected list to contain the kind of the last make_unique"); + auto Kind = KindList.getHead(); + if (Kind == MakeUniqueKind::ForOverwrite) { + auto RHSVal = C.getSValBuilder().makeNull(); + State = State->set(ThisRegion, RHSVal); + } else { + // TODO: Encode information that the inner pointer for + // unique_ptr made by std::make_unique is *not* null + } + State = State->set(KindList.getTail()); + C.addTransition(State); +} + void SmartPtrModeling::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState();