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