23
23
#include " llvm/Support/Debug.h"
24
24
#include " llvm/Support/TimeProfiler.h"
25
25
#include < cstdint>
26
+ #include < memory>
26
27
27
28
namespace clang ::lifetimes {
28
29
namespace internal {
29
- namespace {
30
- template <typename Tag>
31
- inline llvm::raw_ostream &operator <<(llvm::raw_ostream &OS, ID<Tag> ID) {
32
- return OS << ID.Value ;
33
- }
34
- } // namespace
35
30
36
31
// / Represents the storage location being borrowed, e.g., a specific stack
37
32
// / variable.
@@ -832,6 +827,91 @@ class LoanPropagationAnalysis
832
827
}
833
828
};
834
829
830
+ // ========================================================================= //
831
+ // Expired Loans Analysis
832
+ // ========================================================================= //
833
+
834
+ // / The dataflow lattice for tracking the set of expired loans.
835
+ struct ExpiredLattice {
836
+ LoanSet Expired;
837
+
838
+ ExpiredLattice () : Expired(nullptr ) {};
839
+ explicit ExpiredLattice (LoanSet S) : Expired(S) {}
840
+
841
+ bool operator ==(const ExpiredLattice &Other) const {
842
+ return Expired == Other.Expired ;
843
+ }
844
+ bool operator !=(const ExpiredLattice &Other) const {
845
+ return !(*this == Other);
846
+ }
847
+
848
+ void dump (llvm::raw_ostream &OS) const {
849
+ OS << " ExpiredLattice State:\n " ;
850
+ if (Expired.isEmpty ())
851
+ OS << " <empty>\n " ;
852
+ for (const LoanID &LID : Expired)
853
+ OS << " Loan " << LID << " is expired\n " ;
854
+ }
855
+ };
856
+
857
+ // / The analysis that tracks which loans have expired.
858
+ class ExpiredLoansAnalysis
859
+ : public DataflowAnalysis<ExpiredLoansAnalysis, ExpiredLattice,
860
+ Direction::Forward> {
861
+
862
+ LoanSet::Factory &Factory;
863
+
864
+ public:
865
+ ExpiredLoansAnalysis (const CFG &C, AnalysisDeclContext &AC, FactManager &F,
866
+ LifetimeFactory &Factory)
867
+ : DataflowAnalysis(C, AC, F), Factory(Factory.LoanSetFactory) {}
868
+
869
+ using Base::transfer;
870
+
871
+ StringRef getAnalysisName () const { return " ExpiredLoans" ; }
872
+
873
+ Lattice getInitialState () { return Lattice (Factory.getEmptySet ()); }
874
+
875
+ // / Merges two lattices by taking the union of the expired loan sets.
876
+ Lattice join (Lattice L1, Lattice L2) const {
877
+ return Lattice (utils::join (L1.Expired , L2.Expired , Factory));
878
+ }
879
+
880
+ Lattice transfer (Lattice In, const ExpireFact &F) {
881
+ return Lattice (Factory.add (In.Expired , F.getLoanID ()));
882
+ }
883
+
884
+ // Removes the loan from the set of expired loans.
885
+ //
886
+ // When a loan is re-issued (e.g., in a loop), it is no longer considered
887
+ // expired. A loan can be in the expired set at the point of issue due to
888
+ // the dataflow state from a previous loop iteration being propagated along
889
+ // a backedge in the CFG.
890
+ //
891
+ // Note: This has a subtle false-negative though where a loan from previous
892
+ // iteration is not overwritten by a reissue. This needs careful tracking
893
+ // of loans "across iterations" which can be considered for future
894
+ // enhancements.
895
+ //
896
+ // void foo(int safe) {
897
+ // int* p = &safe;
898
+ // int* q = &safe;
899
+ // while (condition()) {
900
+ // int x = 1;
901
+ // p = &x; // A loan to 'x' is issued to 'p' in every iteration.
902
+ // if (condition()) {
903
+ // q = p;
904
+ // }
905
+ // (void)*p; // OK — 'p' points to 'x' from new iteration.
906
+ // (void)*q; // UaF - 'q' still points to 'x' from previous iteration
907
+ // // which is now destroyed.
908
+ // }
909
+ // }
910
+ Lattice transfer (Lattice In, const IssueFact &F) {
911
+ return Lattice (Factory.remove (In.Expired , F.getLoanID ()));
912
+ }
913
+ };
914
+
835
915
// ========================================================================= //
836
916
// TODO:
837
917
// - Modify loan expiry analysis to answer `bool isExpired(Loan L, Point P)`
@@ -873,6 +953,10 @@ void LifetimeSafetyAnalysis::run() {
873
953
LoanPropagation =
874
954
std::make_unique<LoanPropagationAnalysis>(Cfg, AC, *FactMgr, *Factory);
875
955
LoanPropagation->run ();
956
+
957
+ ExpiredLoans =
958
+ std::make_unique<ExpiredLoansAnalysis>(Cfg, AC, *FactMgr, *Factory);
959
+ ExpiredLoans->run ();
876
960
}
877
961
878
962
LoanSet LifetimeSafetyAnalysis::getLoansAtPoint (OriginID OID,
@@ -881,6 +965,11 @@ LoanSet LifetimeSafetyAnalysis::getLoansAtPoint(OriginID OID,
881
965
return LoanPropagation->getLoans (OID, PP);
882
966
}
883
967
968
+ LoanSet LifetimeSafetyAnalysis::getExpiredLoansAtPoint (ProgramPoint PP) const {
969
+ assert (ExpiredLoans && " ExpiredLoansAnalysis has not been run." );
970
+ return ExpiredLoans->getState (PP).Expired ;
971
+ }
972
+
884
973
std::optional<OriginID>
885
974
LifetimeSafetyAnalysis::getOriginIDForDecl (const ValueDecl *D) const {
886
975
assert (FactMgr && " FactManager not initialized" );
0 commit comments