4646
4747#include " AllocationState.h"
4848#include " InterCheckerAPI.h"
49+ #include " NoOwnershipChangeVisitor.h"
4950#include " clang/AST/Attr.h"
5051#include " clang/AST/DeclCXX.h"
5152#include " clang/AST/DeclTemplate.h"
7980#include " clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
8081#include " llvm/ADT/STLExtras.h"
8182#include " llvm/ADT/SetOperations.h"
82- #include " llvm/ADT/SmallString.h"
8383#include " llvm/ADT/StringExtras.h"
8484#include " llvm/Support/Casting.h"
8585#include " llvm/Support/Compiler.h"
8686#include " llvm/Support/ErrorHandling.h"
8787#include " llvm/Support/raw_ostream.h"
88- #include < climits>
8988#include < functional>
9089#include < optional>
9190#include < utility>
@@ -414,7 +413,7 @@ class MallocChecker
414413 bool isFreeingCall (const CallEvent &Call) const ;
415414 static bool isFreeingOwnershipAttrCall (const FunctionDecl *Func);
416415
417- friend class NoOwnershipChangeVisitor ;
416+ friend class NoMemOwnershipChangeVisitor ;
418417
419418 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
420419 {{CDM::CLibrary, {" alloca" }, 1 }, &MallocChecker::checkAlloca},
@@ -765,61 +764,8 @@ class MallocChecker
765764// ===----------------------------------------------------------------------===//
766765
767766namespace {
768- class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
769- // The symbol whose (lack of) ownership change we are interested in.
770- SymbolRef Sym;
771- const MallocChecker &Checker;
772- using OwnerSet = llvm::SmallPtrSet<const MemRegion *, 8 >;
773-
774- // Collect which entities point to the allocated memory, and could be
775- // responsible for deallocating it.
776- class OwnershipBindingsHandler : public StoreManager ::BindingsHandler {
777- SymbolRef Sym;
778- OwnerSet &Owners;
779-
780- public:
781- OwnershipBindingsHandler (SymbolRef Sym, OwnerSet &Owners)
782- : Sym(Sym), Owners(Owners) {}
783-
784- bool HandleBinding (StoreManager &SMgr, Store Store, const MemRegion *Region,
785- SVal Val) override {
786- if (Val.getAsSymbol () == Sym)
787- Owners.insert (Region);
788- return true ;
789- }
790-
791- LLVM_DUMP_METHOD void dump () const { dumpToStream (llvm::errs ()); }
792- LLVM_DUMP_METHOD void dumpToStream (llvm::raw_ostream &out) const {
793- out << " Owners: {\n " ;
794- for (const MemRegion *Owner : Owners) {
795- out << " " ;
796- Owner->dumpToStream (out);
797- out << " ,\n " ;
798- }
799- out << " }\n " ;
800- }
801- };
802-
767+ class NoMemOwnershipChangeVisitor final : public NoOwnershipChangeVisitor {
803768protected:
804- OwnerSet getOwnersAtNode (const ExplodedNode *N) {
805- OwnerSet Ret;
806-
807- ProgramStateRef State = N->getState ();
808- OwnershipBindingsHandler Handler{Sym, Ret};
809- State->getStateManager ().getStoreManager ().iterBindings (State->getStore (),
810- Handler);
811- return Ret;
812- }
813-
814- LLVM_DUMP_METHOD static std::string
815- getFunctionName (const ExplodedNode *CallEnterN) {
816- if (const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
817- CallEnterN->getLocationAs <CallEnter>()->getCallExpr ()))
818- if (const FunctionDecl *FD = CE->getDirectCallee ())
819- return FD->getQualifiedNameAsString ();
820- return " " ;
821- }
822-
823769 // / Syntactically checks whether the callee is a deallocating function. Since
824770 // / we have no path-sensitive information on this call (we would need a
825771 // / CallEvent instead of a CallExpr for that), its possible that a
@@ -828,8 +774,9 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
828774 // / See namespace `memory_passed_to_fn_call_free_through_fn_ptr` in
829775 // / clang/test/Analysis/NewDeleteLeaks.cpp.
830776 bool isFreeingCallAsWritten (const CallExpr &Call) const {
831- if (Checker.FreeingMemFnMap .lookupAsWritten (Call) ||
832- Checker.ReallocatingMemFnMap .lookupAsWritten (Call))
777+ const auto *MallocChk = static_cast <const MallocChecker *>(&Checker);
778+ if (MallocChk->FreeingMemFnMap .lookupAsWritten (Call) ||
779+ MallocChk->ReallocatingMemFnMap .lookupAsWritten (Call))
833780 return true ;
834781
835782 if (const auto *Func =
@@ -839,23 +786,21 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
839786 return false ;
840787 }
841788
789+ bool hasResourceStateChanged (ProgramStateRef CallEnterState,
790+ ProgramStateRef CallExitEndState) final {
791+ return CallEnterState->get <RegionState>(Sym) !=
792+ CallExitEndState->get <RegionState>(Sym);
793+ }
794+
842795 // / Heuristically guess whether the callee intended to free memory. This is
843796 // / done syntactically, because we are trying to argue about alternative
844797 // / paths of execution, and as a consequence we don't have path-sensitive
845798 // / information.
846- bool doesFnIntendToHandleOwnership (const Decl *Callee, ASTContext &ACtx) {
799+ bool doesFnIntendToHandleOwnership (const Decl *Callee,
800+ ASTContext &ACtx) final {
847801 using namespace clang ::ast_matchers;
848802 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
849803
850- // Given that the stack frame was entered, the body should always be
851- // theoretically obtainable. In case of body farms, the synthesized body
852- // is not attached to declaration, thus triggering the '!FD->hasBody()'
853- // branch. That said, would a synthesized body ever intend to handle
854- // ownership? As of today they don't. And if they did, how would we
855- // put notes inside it, given that it doesn't match any source locations?
856- if (!FD || !FD->hasBody ())
857- return false ;
858-
859804 auto Matches = match (findAll (stmt (anyOf (cxxDeleteExpr ().bind (" delete" ),
860805 callExpr ().bind (" call" )))),
861806 *FD->getBody (), ACtx);
@@ -873,30 +818,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
873818 return false ;
874819 }
875820
876- bool wasModifiedInFunction (const ExplodedNode *CallEnterN,
877- const ExplodedNode *CallExitEndN) override {
878- if (!doesFnIntendToHandleOwnership (
879- CallExitEndN->getFirstPred ()->getLocationContext ()->getDecl (),
880- CallExitEndN->getState ()->getAnalysisManager ().getASTContext ()))
881- return true ;
882-
883- if (CallEnterN->getState ()->get <RegionState>(Sym) !=
884- CallExitEndN->getState ()->get <RegionState>(Sym))
885- return true ;
886-
887- OwnerSet CurrOwners = getOwnersAtNode (CallEnterN);
888- OwnerSet ExitOwners = getOwnersAtNode (CallExitEndN);
889-
890- // Owners in the current set may be purged from the analyzer later on.
891- // If a variable is dead (is not referenced directly or indirectly after
892- // some point), it will be removed from the Store before the end of its
893- // actual lifetime.
894- // This means that if the ownership status didn't change, CurrOwners
895- // must be a superset of, but not necessarily equal to ExitOwners.
896- return !llvm::set_is_subset (ExitOwners, CurrOwners);
897- }
898-
899- static PathDiagnosticPieceRef emitNote (const ExplodedNode *N) {
821+ PathDiagnosticPieceRef emitNote (const ExplodedNode *N) final {
900822 PathDiagnosticLocation L = PathDiagnosticLocation::create (
901823 N->getLocation (),
902824 N->getState ()->getStateManager ().getContext ().getSourceManager ());
@@ -905,42 +827,9 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
905827 " later deallocation" );
906828 }
907829
908- PathDiagnosticPieceRef
909- maybeEmitNoteForObjCSelf (PathSensitiveBugReport &R,
910- const ObjCMethodCall &Call,
911- const ExplodedNode *N) override {
912- // TODO: Implement.
913- return nullptr ;
914- }
915-
916- PathDiagnosticPieceRef
917- maybeEmitNoteForCXXThis (PathSensitiveBugReport &R,
918- const CXXConstructorCall &Call,
919- const ExplodedNode *N) override {
920- // TODO: Implement.
921- return nullptr ;
922- }
923-
924- PathDiagnosticPieceRef
925- maybeEmitNoteForParameters (PathSensitiveBugReport &R, const CallEvent &Call,
926- const ExplodedNode *N) override {
927- // TODO: Factor the logic of "what constitutes as an entity being passed
928- // into a function call" out by reusing the code in
929- // NoStoreFuncVisitor::maybeEmitNoteForParameters, maybe by incorporating
930- // the printing technology in UninitializedObject's FieldChainInfo.
931- ArrayRef<ParmVarDecl *> Parameters = Call.parameters ();
932- for (unsigned I = 0 ; I < Call.getNumArgs () && I < Parameters.size (); ++I) {
933- SVal V = Call.getArgSVal (I);
934- if (V.getAsSymbol () == Sym)
935- return emitNote (N);
936- }
937- return nullptr ;
938- }
939-
940830public:
941- NoOwnershipChangeVisitor (SymbolRef Sym, const MallocChecker *Checker)
942- : NoStateChangeFuncVisitor(bugreporter::TrackingKind::Thorough), Sym(Sym),
943- Checker (*Checker) {}
831+ NoMemOwnershipChangeVisitor (SymbolRef Sym, const MallocChecker *Checker)
832+ : NoOwnershipChangeVisitor(Sym, Checker) {}
944833
945834 void Profile (llvm::FoldingSetNodeID &ID) const override {
946835 static int Tag = 0 ;
@@ -2949,7 +2838,7 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
29492838 R->markInteresting (Sym);
29502839 R->addVisitor <MallocBugVisitor>(Sym, true );
29512840 if (ShouldRegisterNoOwnershipChangeVisitor)
2952- R->addVisitor <NoOwnershipChangeVisitor >(Sym, this );
2841+ R->addVisitor <NoMemOwnershipChangeVisitor >(Sym, this );
29532842 C.emitReport (std::move (R));
29542843}
29552844
0 commit comments