clang 23.0.0git
Facts.h
Go to the documentation of this file.
1//===- Facts.h - Lifetime Analysis Facts and Fact Manager ------*- 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// This file defines Facts, which are atomic lifetime-relevant events (such as
10// loan issuance, loan expiration, origin flow, and use), and the FactManager,
11// which manages the storage and retrieval of facts for each CFG block.
12//
13//===----------------------------------------------------------------------===//
14#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
15#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
16
17#include "clang/AST/Decl.h"
22#include "clang/Analysis/CFG.h"
23#include "llvm/ADT/STLFunctionalExtras.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/Support/Debug.h"
26#include <cstdint>
27#include <optional>
28
30
32
33/// An abstract base class for a single, atomic lifetime-relevant event.
34class Fact {
35
36public:
37 enum class Kind : uint8_t {
38 /// A new loan is issued from a borrow expression (e.g., &x).
40 /// A loan expires as its underlying storage is freed (e.g., variable goes
41 /// out of scope).
43 /// An origin is propagated from a source to a destination (e.g., p = q).
44 /// This can also optionally kill the destination origin before flowing into
45 /// it. Otherwise, the source's loan set is merged into the destination's
46 /// loan set.
48 /// An origin is used (eg. appears as l-value expression like DeclRefExpr).
50 /// An origin that is moved (e.g., passed to an rvalue reference parameter).
52 /// A marker for a specific point in the code, for testing.
54 /// An origin that escapes the function scope (e.g., via return).
56 /// An origin is invalidated (e.g. vector resized).
58 /// All loans of an origin are cleared.
60 };
61
62private:
63 Kind K;
64 FactID ID;
65
66protected:
67 Fact(Kind K) : K(K) {}
68
69public:
70 virtual ~Fact() = default;
71 Kind getKind() const { return K; }
72
73 void setID(FactID ID) { this->ID = ID; }
74 FactID getID() const { return ID; }
75
76 template <typename T> const T *getAs() const {
77 if (T::classof(this))
78 return static_cast<const T *>(this);
79 return nullptr;
80 }
81
82 virtual void dump(llvm::raw_ostream &OS, const LoanManager &,
83 const OriginManager &) const;
84};
85
86/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
87/// `Fact`. identified by a lifetime-related event (`Fact`).
88///
89/// A `ProgramPoint` has "after" semantics: it represents the location
90/// immediately after its corresponding `Fact`.
91using ProgramPoint = const Fact *;
92
93class IssueFact : public Fact {
94 LoanID LID;
95 OriginID OID;
96
97public:
98 static bool classof(const Fact *F) { return F->getKind() == Kind::Issue; }
99
100 IssueFact(LoanID LID, OriginID OID) : Fact(Kind::Issue), LID(LID), OID(OID) {}
101 LoanID getLoanID() const { return LID; }
102 OriginID getOriginID() const { return OID; }
103 void dump(llvm::raw_ostream &OS, const LoanManager &LM,
104 const OriginManager &OM) const override;
105};
106
107/// When an AccessPath expires (e.g., a variable goes out of scope), all loans
108/// that are associated with this path expire. For example, if `x` expires, then
109/// the loan to `x` expires.
110class ExpireFact : public Fact {
111 // The access path that expires.
112 AccessPath AP;
113
114 // Expired origin (e.g., its variable goes out of scope).
115 std::optional<OriginID> OID;
116 SourceLocation ExpiryLoc;
117
118public:
119 static bool classof(const Fact *F) { return F->getKind() == Kind::Expire; }
120
122 std::optional<OriginID> OID = std::nullopt)
123 : Fact(Kind::Expire), AP(AP), OID(OID), ExpiryLoc(ExpiryLoc) {}
124
125 const AccessPath &getAccessPath() const { return AP; }
126 std::optional<OriginID> getOriginID() const { return OID; }
127 SourceLocation getExpiryLoc() const { return ExpiryLoc; }
128
129 void dump(llvm::raw_ostream &OS, const LoanManager &LM,
130 const OriginManager &OM) const override;
131};
132
133class OriginFlowFact : public Fact {
134 OriginID OIDDest;
135 OriginID OIDSrc;
136 // True if the destination origin should be killed (i.e., its current loans
137 // cleared) before the source origin's loans are flowed into it.
138 bool KillDest;
139
140public:
141 static bool classof(const Fact *F) {
142 return F->getKind() == Kind::OriginFlow;
143 }
144
145 OriginFlowFact(OriginID OIDDest, OriginID OIDSrc, bool KillDest)
146 : Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc),
147 KillDest(KillDest) {}
148
149 OriginID getDestOriginID() const { return OIDDest; }
150 OriginID getSrcOriginID() const { return OIDSrc; }
151 bool getKillDest() const { return KillDest; }
152
153 void dump(llvm::raw_ostream &OS, const LoanManager &,
154 const OriginManager &OM) const override;
155};
156
157/// Represents that an origin escapes the current scope through various means.
158/// This is the base class for different escape scenarios.
159class OriginEscapesFact : public Fact {
160 OriginID OID;
161
162public:
163 /// The way an origin can escape the current scope.
164 enum class EscapeKind : uint8_t {
165 Return, /// Escapes via return statement.
166 Field, /// Escapes via assignment to a field.
167 Global, /// Escapes via assignment to global storage.
169
170 static bool classof(const Fact *F) {
171 return F->getKind() == Kind::OriginEscapes;
172 }
173
176 OriginID getEscapedOriginID() const { return OID; }
177 EscapeKind getEscapeKind() const { return EscKind; }
178};
179
180/// Represents that an origin escapes via a return statement.
182 const Expr *ReturnExpr;
183
184public:
185 ReturnEscapeFact(OriginID OID, const Expr *ReturnExpr)
186 : OriginEscapesFact(OID, EscapeKind::Return), ReturnExpr(ReturnExpr) {}
187
188 static bool classof(const Fact *F) {
189 return F->getKind() == Kind::OriginEscapes &&
190 static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
192 }
193 const Expr *getReturnExpr() const { return ReturnExpr; };
194 void dump(llvm::raw_ostream &OS, const LoanManager &,
195 const OriginManager &OM) const override;
196};
197
198/// Represents that an origin escapes via assignment to a field.
199/// Example: `this->view = local_var;` where local_var outlives the assignment
200/// but not the object containing the field.
202 const FieldDecl *FDecl;
203
204public:
206 : OriginEscapesFact(OID, EscapeKind::Field), FDecl(FDecl) {}
207
208 static bool classof(const Fact *F) {
209 return F->getKind() == Kind::OriginEscapes &&
210 static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
212 }
213 const FieldDecl *getFieldDecl() const { return FDecl; };
214 void dump(llvm::raw_ostream &OS, const LoanManager &,
215 const OriginManager &OM) const override;
216};
217
218/// Represents that an origin escapes via assignment to global or static
219/// storage. Example: `global_storage = local_var;`
221 const VarDecl *Global;
222
223public:
225 : OriginEscapesFact(OID, EscapeKind::Global), Global(VDecl) {}
226
227 static bool classof(const Fact *F) {
228 return F->getKind() == Kind::OriginEscapes &&
229 static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
231 }
232 const VarDecl *getGlobal() const { return Global; };
233 void dump(llvm::raw_ostream &OS, const LoanManager &,
234 const OriginManager &OM) const override;
235};
236
237class UseFact : public Fact {
238 const Expr *UseExpr;
239 const OriginList *OList;
240 // True if this use is a write operation (e.g., left-hand side of assignment).
241 // Write operations are exempted from use-after-free checks.
242 bool IsWritten = false;
243
244public:
245 static bool classof(const Fact *F) { return F->getKind() == Kind::Use; }
246
247 UseFact(const Expr *UseExpr, const OriginList *OList)
248 : Fact(Kind::Use), UseExpr(UseExpr), OList(OList) {}
249
250 const OriginList *getUsedOrigins() const { return OList; }
251 void setUsedOrigins(const OriginList *NewList) { OList = NewList; }
252 const Expr *getUseExpr() const { return UseExpr; }
253 void markAsWritten() { IsWritten = true; }
254 bool isWritten() const { return IsWritten; }
255
256 void dump(llvm::raw_ostream &OS, const LoanManager &,
257 const OriginManager &OM) const override;
258};
259
260/// Represents that an origin's storage has been invalidated by a container
261/// operation (e.g., vector::push_back may reallocate, invalidating iterators).
262/// Created when a container method that may invalidate references/iterators
263/// is called on the container.
265 OriginID OID;
266 const Expr *InvalidationExpr;
267
268public:
269 static bool classof(const Fact *F) {
270 return F->getKind() == Kind::InvalidateOrigin;
271 }
272
273 InvalidateOriginFact(OriginID OID, const Expr *InvalidationExpr)
274 : Fact(Kind::InvalidateOrigin), OID(OID),
275 InvalidationExpr(InvalidationExpr) {}
276
277 OriginID getInvalidatedOrigin() const { return OID; }
278 const Expr *getInvalidationExpr() const { return InvalidationExpr; }
279 void dump(llvm::raw_ostream &OS, const LoanManager &,
280 const OriginManager &OM) const override;
281};
282
283/// Top-level origin of the expression which was found to be moved, e.g, when
284/// being used as an argument to an r-value reference parameter.
285class MovedOriginFact : public Fact {
286 const OriginID MovedOrigin;
287 const Expr *MoveExpr;
288
289public:
290 static bool classof(const Fact *F) {
291 return F->getKind() == Kind::MovedOrigin;
292 }
293
294 MovedOriginFact(const Expr *MoveExpr, OriginID MovedOrigin)
295 : Fact(Kind::MovedOrigin), MovedOrigin(MovedOrigin), MoveExpr(MoveExpr) {}
296
297 OriginID getMovedOrigin() const { return MovedOrigin; }
298 const Expr *getMoveExpr() const { return MoveExpr; }
299
300 void dump(llvm::raw_ostream &OS, const LoanManager &,
301 const OriginManager &OM) const override;
302};
303
304/// A dummy-fact used to mark a specific point in the code for testing.
305/// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
306class TestPointFact : public Fact {
307 StringRef Annotation;
308
309public:
310 static bool classof(const Fact *F) { return F->getKind() == Kind::TestPoint; }
311
312 explicit TestPointFact(StringRef Annotation)
313 : Fact(Kind::TestPoint), Annotation(Annotation) {}
314
315 StringRef getAnnotation() const { return Annotation; }
316
317 void dump(llvm::raw_ostream &OS, const LoanManager &,
318 const OriginManager &) const override;
319};
320
321/// All loans are cleared from an origin (e.g., assigning a callable without
322/// tracked origins to std::function).
323class KillOriginFact : public Fact {
324 OriginID OID;
325
326public:
327 static bool classof(const Fact *F) {
328 return F->getKind() == Kind::KillOrigin;
329 }
330
332
333 OriginID getKilledOrigin() const { return OID; }
334
335 void dump(llvm::raw_ostream &OS, const LoanManager &,
336 const OriginManager &OM) const override;
337};
338
340public:
341 FactManager(const AnalysisDeclContext &AC, const CFG &Cfg) : OriginMgr(AC) {
342 BlockToFacts.resize(Cfg.getNumBlockIDs());
343 }
344
346 return BlockToFacts[B->getBlockID()];
347 }
348
350 if (!NewFacts.empty())
351 BlockToFacts[B->getBlockID()].assign(NewFacts.begin(), NewFacts.end());
352 }
353
354 template <typename FactType, typename... Args>
355 FactType *createFact(Args &&...args) {
356 void *Mem = FactAllocator.Allocate<FactType>();
357 FactType *Res = new (Mem) FactType(std::forward<Args>(args)...);
358 Res->setID(NextFactID++);
359 return Res;
360 }
361
362 void dump(const CFG &Cfg, AnalysisDeclContext &AC) const;
363
364 /// Retrieves program points that were specially marked in the source code
365 /// for testing.
366 ///
367 /// The analysis recognizes special function calls of the form
368 /// `void("__lifetime_test_point_<name>")` as test points. This method returns
369 /// a map from the annotation string (<name>) to the corresponding
370 /// `ProgramPoint`. This allows test harnesses to query the analysis state at
371 /// user-defined locations in the code.
372 /// \note This is intended for testing only.
373 llvm::StringMap<ProgramPoint> getTestPoints() const;
374 /// Retrieves all the facts in the block containing Program Point P.
375 /// \note This is intended for testing only.
377
378 unsigned getNumFacts() const { return NextFactID.Value; }
379
380 LoanManager &getLoanMgr() { return LoanMgr; }
381 const LoanManager &getLoanMgr() const { return LoanMgr; }
382 OriginManager &getOriginMgr() { return OriginMgr; }
383 const OriginManager &getOriginMgr() const { return OriginMgr; }
384
385private:
386 FactID NextFactID{0};
387 LoanManager LoanMgr;
388 OriginManager OriginMgr;
389 /// Facts for each CFG block, indexed by block ID.
391 llvm::BumpPtrAllocator FactAllocator;
392};
393} // namespace clang::lifetimes::internal
394
395#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents a single basic block in a source-level CFG.
Definition CFG.h:632
unsigned getBlockID() const
Definition CFG.h:1134
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1250
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition CFG.h:1443
This represents one expression.
Definition Expr.h:112
Represents a member of a struct/union/class.
Definition Decl.h:3175
Encodes a location in the source.
Represents a variable declaration or definition.
Definition Decl.h:926
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
Definition Loans.h:44
const AccessPath & getAccessPath() const
Definition Facts.h:125
SourceLocation getExpiryLoc() const
Definition Facts.h:127
static bool classof(const Fact *F)
Definition Facts.h:119
ExpireFact(AccessPath AP, SourceLocation ExpiryLoc, std::optional< OriginID > OID=std::nullopt)
Definition Facts.h:121
std::optional< OriginID > getOriginID() const
Definition Facts.h:126
void dump(llvm::raw_ostream &OS, const LoanManager &LM, const OriginManager &OM) const override
Definition Facts.cpp:29
llvm::ArrayRef< const Fact * > getFacts(const CFGBlock *B) const
Definition Facts.h:345
FactType * createFact(Args &&...args)
Definition Facts.h:355
llvm::StringMap< ProgramPoint > getTestPoints() const
Retrieves program points that were specially marked in the source code for testing.
Definition Facts.cpp:113
void dump(const CFG &Cfg, AnalysisDeclContext &AC) const
Definition Facts.cpp:128
void addBlockFacts(const CFGBlock *B, llvm::ArrayRef< Fact * > NewFacts)
Definition Facts.h:349
const OriginManager & getOriginMgr() const
Definition Facts.h:383
const LoanManager & getLoanMgr() const
Definition Facts.h:381
llvm::ArrayRef< const Fact * > getBlockContaining(ProgramPoint P) const
Retrieves all the facts in the block containing Program Point P.
Definition Facts.cpp:147
FactManager(const AnalysisDeclContext &AC, const CFG &Cfg)
Definition Facts.h:341
An abstract base class for a single, atomic lifetime-relevant event.
Definition Facts.h:34
@ InvalidateOrigin
An origin is invalidated (e.g. vector resized).
Definition Facts.h:57
@ TestPoint
A marker for a specific point in the code, for testing.
Definition Facts.h:53
@ Expire
A loan expires as its underlying storage is freed (e.g., variable goes out of scope).
Definition Facts.h:42
@ Issue
A new loan is issued from a borrow expression (e.g., &x).
Definition Facts.h:39
@ OriginFlow
An origin is propagated from a source to a destination (e.g., p = q).
Definition Facts.h:47
@ MovedOrigin
An origin that is moved (e.g., passed to an rvalue reference parameter).
Definition Facts.h:51
@ Use
An origin is used (eg. appears as l-value expression like DeclRefExpr).
Definition Facts.h:49
@ OriginEscapes
An origin that escapes the function scope (e.g., via return).
Definition Facts.h:55
@ KillOrigin
All loans of an origin are cleared.
Definition Facts.h:59
const T * getAs() const
Definition Facts.h:76
virtual void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &) const
Definition Facts.cpp:15
FieldEscapeFact(OriginID OID, const FieldDecl *FDecl)
Definition Facts.h:205
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:66
const FieldDecl * getFieldDecl() const
Definition Facts.h:213
static bool classof(const Fact *F)
Definition Facts.h:208
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:73
GlobalEscapeFact(OriginID OID, const VarDecl *VDecl)
Definition Facts.h:224
static bool classof(const Fact *F)
Definition Facts.h:227
const VarDecl * getGlobal() const
Definition Facts.h:232
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:94
InvalidateOriginFact(OriginID OID, const Expr *InvalidationExpr)
Definition Facts.h:273
void dump(llvm::raw_ostream &OS, const LoanManager &LM, const OriginManager &OM) const override
Definition Facts.cpp:20
IssueFact(LoanID LID, OriginID OID)
Definition Facts.h:100
static bool classof(const Fact *F)
Definition Facts.h:98
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:106
static bool classof(const Fact *F)
Definition Facts.h:327
Manages the creation, storage and retrieval of loans.
Definition Loans.h:129
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:52
static bool classof(const Fact *F)
Definition Facts.h:290
MovedOriginFact(const Expr *MoveExpr, OriginID MovedOrigin)
Definition Facts.h:294
enum clang::lifetimes::internal::OriginEscapesFact::EscapeKind EscKind
EscapeKind
The way an origin can escape the current scope.
Definition Facts.h:164
@ Global
Escapes via assignment to a field.
Definition Facts.h:167
static bool classof(const Fact *F)
Definition Facts.h:170
OriginEscapesFact(OriginID OID, EscapeKind EscKind)
Definition Facts.h:174
static bool classof(const Fact *F)
Definition Facts.h:141
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:40
OriginFlowFact(OriginID OIDDest, OriginID OIDSrc, bool KillDest)
Definition Facts.h:145
A list of origins representing levels of indirection for pointer-like types.
Definition Origins.h:95
Manages the creation, storage, and retrieval of origins for pointer-like variables and expressions.
Definition Origins.h:125
static bool classof(const Fact *F)
Definition Facts.h:188
ReturnEscapeFact(OriginID OID, const Expr *ReturnExpr)
Definition Facts.h:185
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:59
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &) const override
Definition Facts.cpp:101
static bool classof(const Fact *F)
Definition Facts.h:310
TestPointFact(StringRef Annotation)
Definition Facts.h:312
void setUsedOrigins(const OriginList *NewList)
Definition Facts.h:251
const Expr * getUseExpr() const
Definition Facts.h:252
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM) const override
Definition Facts.cpp:80
static bool classof(const Fact *F)
Definition Facts.h:245
UseFact(const Expr *UseExpr, const OriginList *OList)
Definition Facts.h:247
const OriginList * getUsedOrigins() const
Definition Facts.h:250
const Fact * ProgramPoint
A ProgramPoint identifies a location in the CFG by pointing to a specific Fact.
Definition Facts.h:91
utils::ID< struct LoanTag > LoanID
Definition Loans.h:25
utils::ID< struct OriginTag > OriginID
Definition Origins.h:28
utils::ID< struct FactTag > FactID
Definition Facts.h:31
A generic, type-safe wrapper for an ID, distinguished by its Tag type.
Definition Utils.h:21