46
46
47
47
#include " AllocationState.h"
48
48
#include " InterCheckerAPI.h"
49
+ #include " NoOwnershipChangeVisitor.h"
49
50
#include " clang/AST/Attr.h"
50
51
#include " clang/AST/DeclCXX.h"
51
52
#include " clang/AST/DeclTemplate.h"
79
80
#include " clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
80
81
#include " llvm/ADT/STLExtras.h"
81
82
#include " llvm/ADT/SetOperations.h"
82
- #include " llvm/ADT/SmallString.h"
83
83
#include " llvm/ADT/StringExtras.h"
84
84
#include " llvm/Support/Casting.h"
85
85
#include " llvm/Support/Compiler.h"
86
86
#include " llvm/Support/ErrorHandling.h"
87
87
#include " llvm/Support/raw_ostream.h"
88
- #include < climits>
89
88
#include < functional>
90
89
#include < optional>
91
90
#include < utility>
@@ -414,7 +413,7 @@ class MallocChecker
414
413
bool isFreeingCall (const CallEvent &Call) const ;
415
414
static bool isFreeingOwnershipAttrCall (const FunctionDecl *Func);
416
415
417
- friend class NoOwnershipChangeVisitor ;
416
+ friend class NoMemOwnershipChangeVisitor ;
418
417
419
418
CallDescriptionMap<CheckFn> AllocatingMemFnMap{
420
419
{{CDM::CLibrary, {" alloca" }, 1 }, &MallocChecker::checkAlloca},
@@ -765,61 +764,8 @@ class MallocChecker
765
764
// ===----------------------------------------------------------------------===//
766
765
767
766
namespace {
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 {
803
768
protected:
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
-
823
769
// / Syntactically checks whether the callee is a deallocating function. Since
824
770
// / we have no path-sensitive information on this call (we would need a
825
771
// / CallEvent instead of a CallExpr for that), its possible that a
@@ -828,8 +774,9 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
828
774
// / See namespace `memory_passed_to_fn_call_free_through_fn_ptr` in
829
775
// / clang/test/Analysis/NewDeleteLeaks.cpp.
830
776
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))
833
780
return true ;
834
781
835
782
if (const auto *Func =
@@ -839,23 +786,21 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
839
786
return false ;
840
787
}
841
788
789
+ bool hasResourceStateChanged (ProgramStateRef CallEnterState,
790
+ ProgramStateRef CallExitEndState) final {
791
+ return CallEnterState->get <RegionState>(Sym) !=
792
+ CallExitEndState->get <RegionState>(Sym);
793
+ }
794
+
842
795
// / Heuristically guess whether the callee intended to free memory. This is
843
796
// / done syntactically, because we are trying to argue about alternative
844
797
// / paths of execution, and as a consequence we don't have path-sensitive
845
798
// / information.
846
- bool doesFnIntendToHandleOwnership (const Decl *Callee, ASTContext &ACtx) {
799
+ bool doesFnIntendToHandleOwnership (const Decl *Callee,
800
+ ASTContext &ACtx) final {
847
801
using namespace clang ::ast_matchers;
848
802
const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
849
803
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
-
859
804
auto Matches = match (findAll (stmt (anyOf (cxxDeleteExpr ().bind (" delete" ),
860
805
callExpr ().bind (" call" )))),
861
806
*FD->getBody (), ACtx);
@@ -873,30 +818,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
873
818
return false ;
874
819
}
875
820
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 {
900
822
PathDiagnosticLocation L = PathDiagnosticLocation::create (
901
823
N->getLocation (),
902
824
N->getState ()->getStateManager ().getContext ().getSourceManager ());
@@ -905,42 +827,9 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
905
827
" later deallocation" );
906
828
}
907
829
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
-
940
830
public:
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) {}
944
833
945
834
void Profile (llvm::FoldingSetNodeID &ID) const override {
946
835
static int Tag = 0 ;
@@ -2949,7 +2838,7 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
2949
2838
R->markInteresting (Sym);
2950
2839
R->addVisitor <MallocBugVisitor>(Sym, true );
2951
2840
if (ShouldRegisterNoOwnershipChangeVisitor)
2952
- R->addVisitor <NoOwnershipChangeVisitor >(Sym, this );
2841
+ R->addVisitor <NoMemOwnershipChangeVisitor >(Sym, this );
2953
2842
C.emitReport (std::move (R));
2954
2843
}
2955
2844
0 commit comments