Skip to content

Commit 9b403b6

Browse files
committed
lifetime-safety-multi-origin
1 parent 5ed26ad commit 9b403b6

File tree

10 files changed

+487
-296
lines changed

10 files changed

+487
-296
lines changed

clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,19 @@ class ReturnOfOriginFact : public Fact {
152152

153153
class UseFact : public Fact {
154154
const Expr *UseExpr;
155-
OriginID OID;
155+
// The origins of the expression being used.
156+
llvm::SmallVector<OriginID, 1> OIDs;
156157
// True if this use is a write operation (e.g., left-hand side of assignment).
157158
// Write operations are exempted from use-after-free checks.
158159
bool IsWritten = false;
159160

160161
public:
161162
static bool classof(const Fact *F) { return F->getKind() == Kind::Use; }
162163

163-
UseFact(const Expr *UseExpr, OriginManager &OM)
164-
: Fact(Kind::Use), UseExpr(UseExpr), OID(OM.get(*UseExpr)) {}
164+
UseFact(const Expr *UseExpr, llvm::ArrayRef<OriginID> OIDs)
165+
: Fact(Kind::Use), UseExpr(UseExpr), OIDs(OIDs.begin(), OIDs.end()) {}
165166

166-
OriginID getUsedOrigin() const { return OID; }
167+
llvm::ArrayRef<OriginID> getUsedOrigins() const { return OIDs; }
167168
const Expr *getUseExpr() const { return UseExpr; }
168169
void markAsWritten() { IsWritten = true; }
169170
bool isWritten() const { return IsWritten; }

clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,17 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> {
4343
void VisitUnaryOperator(const UnaryOperator *UO);
4444
void VisitReturnStmt(const ReturnStmt *RS);
4545
void VisitBinaryOperator(const BinaryOperator *BO);
46-
void VisitConditionalOperator(const ConditionalOperator *CO);
4746
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE);
4847
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE);
4948
void VisitInitListExpr(const InitListExpr *ILE);
5049
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);
5150

5251
private:
52+
OriginTree *getTree(const ValueDecl &D);
53+
OriginTree *getTree(const Expr &E);
54+
55+
void flow(OriginTree *Dst, OriginTree *Src, bool Kill);
56+
5357
void handleDestructor(const CFGAutomaticObjDtor &DtorOpt);
5458

5559
void handleGSLPointerConstruction(const CXXConstructExpr *CCE);
@@ -64,32 +68,24 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> {
6468

6569
template <typename Destination, typename Source>
6670
void flowOrigin(const Destination &D, const Source &S) {
67-
OriginID DestOID = FactMgr.getOriginMgr().getOrCreate(D);
68-
OriginID SrcOID = FactMgr.getOriginMgr().get(S);
69-
CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
70-
DestOID, SrcOID, /*KillDest=*/false));
71+
flow(getTree(D), getTree(S), /*Kill=*/false);
7172
}
7273

7374
template <typename Destination, typename Source>
7475
void killAndFlowOrigin(const Destination &D, const Source &S) {
75-
OriginID DestOID = FactMgr.getOriginMgr().getOrCreate(D);
76-
OriginID SrcOID = FactMgr.getOriginMgr().get(S);
77-
CurrentBlockFacts.push_back(
78-
FactMgr.createFact<OriginFlowFact>(DestOID, SrcOID, /*KillDest=*/true));
76+
flow(getTree(D), getTree(S), /*Kill=*/true);
7977
}
8078

8179
/// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
8280
/// If so, creates a `TestPointFact` and returns true.
8381
bool handleTestPoint(const CXXFunctionalCastExpr *FCE);
8482

85-
void handleAssignment(const Expr *LHSExpr, const Expr *RHSExpr);
86-
8783
// A DeclRefExpr will be treated as a use of the referenced decl. It will be
8884
// checked for use-after-free unless it is later marked as being written to
8985
// (e.g. on the left-hand side of an assignment).
9086
void handleUse(const DeclRefExpr *DRE);
9187

92-
void markUseAsWrite(const DeclRefExpr *DRE);
88+
void markUseAsWrite(const Expr *E);
9389

9490
FactManager &FactMgr;
9591
AnalysisDeclContext &AC;

clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,41 +52,78 @@ struct Origin {
5252
}
5353
};
5454

55+
/// A tree of origins representing levels of indirection for pointer-like
56+
/// types, or a single origin for non-pointer lvalues.
57+
struct OriginTree {
58+
OriginID OID;
59+
OriginTree *Pointee = nullptr;
60+
61+
OriginTree(OriginID OID) : OID(OID) {}
62+
63+
size_t getDepth() const {
64+
size_t Depth = 1;
65+
const OriginTree *T = this;
66+
while (T->Pointee) {
67+
T = T->Pointee;
68+
Depth++;
69+
}
70+
return Depth;
71+
}
72+
};
73+
74+
bool isGslPointerType(QualType QT);
75+
bool isGslOwnerType(QualType QT);
76+
bool isPointerType(QualType QT);
77+
5578
/// Manages the creation, storage, and retrieval of origins for pointer-like
5679
/// variables and expressions.
5780
class OriginManager {
5881
public:
59-
OriginManager() = default;
82+
/// Gets or creates the OriginTree for a given ValueDecl.
83+
OriginTree *getOrCreateTree(const ValueDecl *D);
6084

61-
Origin &addOrigin(OriginID ID, const clang::ValueDecl &D);
62-
Origin &addOrigin(OriginID ID, const clang::Expr &E);
63-
64-
// TODO: Mark this method as const once we remove the call to getOrCreate.
65-
OriginID get(const Expr &E);
66-
67-
OriginID get(const ValueDecl &D);
68-
69-
OriginID getOrCreate(const Expr &E);
85+
/// Gets or creates the OriginTree for a given Expr.
86+
/// Returns nullptr for rvalues of non-pointer type as these do not have
87+
/// origins.
88+
OriginTree *getOrCreateTree(const Expr *E, ASTContext &Ctx);
7089

7190
const Origin &getOrigin(OriginID ID) const;
7291

7392
llvm::ArrayRef<Origin> getOrigins() const { return AllOrigins; }
7493

75-
OriginID getOrCreate(const ValueDecl &D);
76-
7794
unsigned getNumOrigins() const { return NextOriginID.Value; }
7895

7996
void dump(OriginID OID, llvm::raw_ostream &OS) const;
8097

8198
private:
8299
OriginID getNextOriginID() { return NextOriginID++; }
83100

101+
OriginID createOrigin(const ValueDecl *D) {
102+
OriginID NewID = getNextOriginID();
103+
AllOrigins.emplace_back(NewID, D);
104+
return NewID;
105+
}
106+
107+
OriginID createOrigin(const Expr *E) {
108+
OriginID NewID = getNextOriginID();
109+
AllOrigins.emplace_back(NewID, E);
110+
return NewID;
111+
}
112+
113+
OriginTree *createNode(OriginID OID) {
114+
return new (TreeAllocator.Allocate<OriginTree>()) OriginTree(OID);
115+
}
116+
117+
template <typename T>
118+
OriginTree *buildTreeForType(QualType QT, const T *Node);
119+
84120
OriginID NextOriginID{0};
85-
/// TODO(opt): Profile and evaluate the usefullness of small buffer
121+
/// TODO(opt): Profile and evaluate the usefulness of small buffer
86122
/// optimisation.
87123
llvm::SmallVector<Origin> AllOrigins;
88-
llvm::DenseMap<const clang::ValueDecl *, OriginID> DeclToOriginID;
89-
llvm::DenseMap<const clang::Expr *, OriginID> ExprToOriginID;
124+
llvm::BumpPtrAllocator TreeAllocator;
125+
llvm::DenseMap<const clang::ValueDecl *, OriginTree *> DeclToTreeMap;
126+
llvm::DenseMap<const clang::Expr *, OriginTree *> ExprToTreeMap;
90127
};
91128
} // namespace clang::lifetimes::internal
92129

clang/lib/Analysis/LifetimeSafety/Facts.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ void ReturnOfOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &,
5353
void UseFact::dump(llvm::raw_ostream &OS, const LoanManager &,
5454
const OriginManager &OM) const {
5555
OS << "Use (";
56-
OM.dump(getUsedOrigin(), OS);
56+
for (OriginID OID : getUsedOrigins()) {
57+
OM.dump(OID, OS);
58+
OS << " ";
59+
}
5760
OS << ", " << (isWritten() ? "Write" : "Read") << ")\n";
5861
}
5962

0 commit comments

Comments
 (0)