1e622996eSKristóf Umann //===--------------------------------------------------------------*- C++ -*--// 2e622996eSKristóf Umann // 3e622996eSKristóf Umann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e622996eSKristóf Umann // See https://llvm.org/LICENSE.txt for license information. 5e622996eSKristóf Umann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e622996eSKristóf Umann // 7e622996eSKristóf Umann //===----------------------------------------------------------------------===// 8e622996eSKristóf Umann 9e622996eSKristóf Umann #include "NoOwnershipChangeVisitor.h" 10e622996eSKristóf Umann #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" 11e622996eSKristóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 12e622996eSKristóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 13e622996eSKristóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 14e622996eSKristóf Umann #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" 15e622996eSKristóf Umann #include "llvm/ADT/SetOperations.h" 16e622996eSKristóf Umann 17e622996eSKristóf Umann using namespace clang; 18e622996eSKristóf Umann using namespace ento; 19e622996eSKristóf Umann using OwnerSet = NoOwnershipChangeVisitor::OwnerSet; 20e622996eSKristóf Umann 21*fc4b09d1SKristóf Umann namespace { 22e622996eSKristóf Umann // Collect which entities point to the allocated memory, and could be 23e622996eSKristóf Umann // responsible for deallocating it. 24e622996eSKristóf Umann class OwnershipBindingsHandler : public StoreManager::BindingsHandler { 25e622996eSKristóf Umann SymbolRef Sym; 26e622996eSKristóf Umann OwnerSet &Owners; 27e622996eSKristóf Umann 28e622996eSKristóf Umann public: 29e622996eSKristóf Umann OwnershipBindingsHandler(SymbolRef Sym, OwnerSet &Owners) 30e622996eSKristóf Umann : Sym(Sym), Owners(Owners) {} 31e622996eSKristóf Umann 32e622996eSKristóf Umann bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *Region, 33e622996eSKristóf Umann SVal Val) override { 34e622996eSKristóf Umann if (Val.getAsSymbol() == Sym) 35e622996eSKristóf Umann Owners.insert(Region); 36e622996eSKristóf Umann return true; 37e622996eSKristóf Umann } 38e622996eSKristóf Umann 39e622996eSKristóf Umann LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); } 40e622996eSKristóf Umann LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &out) const { 41e622996eSKristóf Umann out << "Owners: {\n"; 42e622996eSKristóf Umann for (const MemRegion *Owner : Owners) { 43e622996eSKristóf Umann out << " "; 44e622996eSKristóf Umann Owner->dumpToStream(out); 45e622996eSKristóf Umann out << ",\n"; 46e622996eSKristóf Umann } 47e622996eSKristóf Umann out << "}\n"; 48e622996eSKristóf Umann } 49e622996eSKristóf Umann }; 50*fc4b09d1SKristóf Umann } // namespace 51e622996eSKristóf Umann 52e622996eSKristóf Umann OwnerSet NoOwnershipChangeVisitor::getOwnersAtNode(const ExplodedNode *N) { 53e622996eSKristóf Umann OwnerSet Ret; 54e622996eSKristóf Umann 55e622996eSKristóf Umann ProgramStateRef State = N->getState(); 56e622996eSKristóf Umann OwnershipBindingsHandler Handler{Sym, Ret}; 57e622996eSKristóf Umann State->getStateManager().getStoreManager().iterBindings(State->getStore(), 58e622996eSKristóf Umann Handler); 59e622996eSKristóf Umann return Ret; 60e622996eSKristóf Umann } 61e622996eSKristóf Umann 62e622996eSKristóf Umann LLVM_DUMP_METHOD std::string 63e622996eSKristóf Umann NoOwnershipChangeVisitor::getFunctionName(const ExplodedNode *CallEnterN) { 64e622996eSKristóf Umann if (const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>( 65e622996eSKristóf Umann CallEnterN->getLocationAs<CallEnter>()->getCallExpr())) 66e622996eSKristóf Umann if (const FunctionDecl *FD = CE->getDirectCallee()) 67e622996eSKristóf Umann return FD->getQualifiedNameAsString(); 68e622996eSKristóf Umann return ""; 69e622996eSKristóf Umann } 70e622996eSKristóf Umann 71e622996eSKristóf Umann bool NoOwnershipChangeVisitor::wasModifiedInFunction( 72e622996eSKristóf Umann const ExplodedNode *CallEnterN, const ExplodedNode *CallExitEndN) { 73e622996eSKristóf Umann const Decl *Callee = 74e622996eSKristóf Umann CallExitEndN->getFirstPred()->getLocationContext()->getDecl(); 75e622996eSKristóf Umann if (!doesFnIntendToHandleOwnership( 76e622996eSKristóf Umann Callee, 77e622996eSKristóf Umann CallExitEndN->getState()->getAnalysisManager().getASTContext())) 78e622996eSKristóf Umann return true; 79e622996eSKristóf Umann 80e622996eSKristóf Umann if (hasResourceStateChanged(CallEnterN->getState(), CallExitEndN->getState())) 81e622996eSKristóf Umann return true; 82e622996eSKristóf Umann 83e622996eSKristóf Umann OwnerSet CurrOwners = getOwnersAtNode(CallEnterN); 84e622996eSKristóf Umann OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN); 85e622996eSKristóf Umann 86e622996eSKristóf Umann // Owners in the current set may be purged from the analyzer later on. 87e622996eSKristóf Umann // If a variable is dead (is not referenced directly or indirectly after 88e622996eSKristóf Umann // some point), it will be removed from the Store before the end of its 89e622996eSKristóf Umann // actual lifetime. 90e622996eSKristóf Umann // This means that if the ownership status didn't change, CurrOwners 91e622996eSKristóf Umann // must be a superset of, but not necessarily equal to ExitOwners. 92e622996eSKristóf Umann return !llvm::set_is_subset(ExitOwners, CurrOwners); 93e622996eSKristóf Umann } 94e622996eSKristóf Umann 95e622996eSKristóf Umann PathDiagnosticPieceRef NoOwnershipChangeVisitor::maybeEmitNoteForParameters( 96e622996eSKristóf Umann PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N) { 97e622996eSKristóf Umann // TODO: Factor the logic of "what constitutes as an entity being passed 98e622996eSKristóf Umann // into a function call" out by reusing the code in 99e622996eSKristóf Umann // NoStoreFuncVisitor::maybeEmitNoteForParameters, maybe by incorporating 100e622996eSKristóf Umann // the printing technology in UninitializedObject's FieldChainInfo. 101e622996eSKristóf Umann ArrayRef<ParmVarDecl *> Parameters = Call.parameters(); 102e622996eSKristóf Umann for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) { 103e622996eSKristóf Umann SVal V = Call.getArgSVal(I); 104e622996eSKristóf Umann if (V.getAsSymbol() == Sym) 105e622996eSKristóf Umann return emitNote(N); 106e622996eSKristóf Umann } 107e622996eSKristóf Umann return nullptr; 108e622996eSKristóf Umann } 109