clang 24.0.0git
FactsGenerator.cpp
Go to the documentation of this file.
1//===- FactsGenerator.cpp - Lifetime Facts Generation -----------*- 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#include <cassert>
10#include <string>
11
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/Expr.h"
15#include "clang/AST/ExprCXX.h"
22#include "clang/Analysis/CFG.h"
24#include "llvm/ADT/ArrayRef.h"
25#include "llvm/ADT/STLExtras.h"
26#include "llvm/Support/Casting.h"
27#include "llvm/Support/Signals.h"
28#include "llvm/Support/TimeProfiler.h"
29
31using llvm::isa_and_present;
32
33OriginList *FactsGenerator::getOriginsList(const ValueDecl &D) {
34 return FactMgr.getOriginMgr().getOrCreateList(&D);
35}
36OriginList *FactsGenerator::getOriginsList(const Expr &E) {
37 return FactMgr.getOriginMgr().getOrCreateList(&E);
38}
39
40bool FactsGenerator::hasOrigins(QualType QT) const {
41 return FactMgr.getOriginMgr().hasOrigins(QT);
42}
43
44bool FactsGenerator::hasOrigins(const Expr *E) const {
45 return FactMgr.getOriginMgr().hasOrigins(E);
46}
47
48/// Propagates origin information from Src to Dst through all levels of
49/// indirection, creating OriginFlowFacts at each level.
50///
51/// This function enforces a critical type-safety invariant: both lists must
52/// have the same shape (same depth/structure). This invariant ensures that
53/// origins flow only between compatible types during expression evaluation.
54///
55/// Examples:
56/// - `int* p = &x;` flows origins from `&x` (depth 1) to `p` (depth 1)
57/// - `int** pp = &p;` flows origins from `&p` (depth 2) to `pp` (depth 2)
58/// * Level 1: pp <- p's address
59/// * Level 2: (*pp) <- what p points to (i.e., &x)
60/// - `View v = obj;` flows origins from `obj` (depth 1) to `v` (depth 1)
61///
62/// \param Dst The destination origin list.
63/// \param Src The source origin list.
64/// \param Kill If true, the destination's existing loans are killed before
65/// flowing.
66/// \param Block Optional. If provided, the generated flow facts are appended to
67/// this specific CFG block. Otherwise, they are appended to the
68/// current block being visited.
69void FactsGenerator::flow(OriginList *Dst, OriginList *Src, bool Kill,
70 const CFGBlock *Block) {
71 if (!Dst)
72 return;
73 assert(Src &&
74 "Dst is non-null but Src is null. List must have the same length");
75 assert(Dst->getLength() == Src->getLength() &&
76 "Lists must have the same length");
77
78 while (Dst && Src) {
79 Fact *F = FactMgr.createFact<OriginFlowFact>(Dst->getOuterOriginID(),
80 Src->getOuterOriginID(), Kill);
81 if (Block)
82 FactMgr.appendBlockFact(Block, F);
83 else
84 CurrentBlockFacts.push_back(F);
85 Dst = Dst->peelOuterOrigin();
86 Src = Src->peelOuterOrigin();
87 }
88}
89
90/// Creates a loan for the storage path of a given declaration reference.
91/// This function should be called whenever a DeclRefExpr represents a borrow.
92/// \param DRE The declaration reference expression that initiates the borrow.
93/// \return The new Loan on success, nullptr otherwise.
94static const Loan *createLoan(FactManager &FactMgr, const DeclRefExpr *DRE) {
95 const ValueDecl *VD = DRE->getDecl();
96 AccessPath Path(VD);
97 // The loan is created at the location of the DeclRefExpr.
98 return FactMgr.getLoanMgr().createLoan(Path, DRE);
99}
100
101/// Creates a loan for the storage location of a temporary object.
102/// \param MTE The MaterializeTemporaryExpr that represents the temporary
103/// binding. \return The new Loan.
104static const Loan *createLoan(FactManager &FactMgr,
105 const MaterializeTemporaryExpr *MTE) {
106 AccessPath Path(MTE);
107 return FactMgr.getLoanMgr().createLoan(Path, MTE);
108}
109
110/// Creates a loan for an allocation through 'new'
111/// \param NE The CXXNewExpr that represents the allocation
112/// \return The new Loan on success, nullptr otherwise
113static const Loan *createLoan(FactManager &FactMgr, const CXXNewExpr *NE) {
114 AccessPath Path(NE);
115 return FactMgr.getLoanMgr().createLoan(Path, NE);
116}
117
119 llvm::TimeTraceScope TimeProfile("FactGenerator");
120 const CFG &Cfg = *AC.getCFG();
121 llvm::SmallVector<Fact *> PlaceholderLoanFacts = issuePlaceholderLoans();
122 // Iterate through the CFG blocks in reverse post-order to ensure that
123 // initializations and destructions are processed in the correct sequence.
124 for (const CFGBlock *Block : *AC.getAnalysis<PostOrderCFGView>()) {
125 CurrentBlockFacts.clear();
126 EscapesInCurrentBlock.clear();
127 CurrentBlock = Block;
128 if (Block == &Cfg.getEntry())
129 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
130 PlaceholderLoanFacts.end());
131 for (unsigned I = 0; I < Block->size(); ++I) {
132 const CFGElement &Element = Block->Elements[I];
133 if (std::optional<CFGStmt> CS = Element.getAs<CFGStmt>())
134 Visit(CS->getStmt());
135 else if (std::optional<CFGInitializer> Initializer =
136 Element.getAs<CFGInitializer>())
137 handleCXXCtorInitializer(Initializer->getInitializer());
138 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
139 Element.getAs<CFGLifetimeEnds>())
140 handleLifetimeEnds(*LifetimeEnds);
141 else if (std::optional<CFGFullExprCleanup> FullExprCleanup =
142 Element.getAs<CFGFullExprCleanup>()) {
143 handleFullExprCleanup(*FullExprCleanup);
144 }
145 }
146 if (Block == &Cfg.getExit())
147 handleExitBlock();
148
149 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
150 EscapesInCurrentBlock.end());
151 FactMgr.addBlockFacts(Block, CurrentBlockFacts);
152 }
153 FactMgr.computePersistentOrigins(Cfg);
154}
155
156OriginList *FactsGenerator::readValue(const Expr *E) {
157 OriginList *List = getOriginsList(*E);
158 if (!List)
159 return nullptr;
160 if (!E->isGLValue())
161 return List;
162 handleAccess(E);
163 return List->peelOuterOrigin();
164}
165
167 for (const Decl *D : DS->decls())
168 if (const auto *VD = dyn_cast<VarDecl>(D))
169 if (const Expr *InitExpr = VD->getInit()) {
170 OriginList *VDList = getOriginsList(*VD);
171 if (!VDList)
172 continue;
173 OriginList *InitList = getOriginsList(*InitExpr);
174 assert(InitList && "VarDecl had origins but InitExpr did not");
175 flow(VDList, InitList, /*Kill=*/true);
176 }
177}
178
180 // Skip function references as their lifetimes are not interesting. Skip non
181 // GLValues (like EnumConstants).
182 if (DRE->getFoundDecl()->isFunctionOrFunctionTemplate() || !DRE->isGLValue())
183 return;
184 // For all declarations with storage (non-references), we issue a loan
185 // representing the borrow of the variable's storage itself.
186 //
187 // Examples:
188 // - `int x; x` issues loan to x's storage
189 // - `int* p; p` issues loan to p's storage (the pointer variable)
190 // - `View v; v` issues loan to v's storage (the view object)
191 // - `int& r = x; r` issues no loan (r has no storage, it's an alias to x)
192 if (doesDeclHaveStorage(DRE->getDecl())) {
193 const Loan *L = createLoan(FactMgr, DRE);
194 assert(L);
195 OriginList *List = getOriginsList(*DRE);
196 assert(List &&
197 "gl-value DRE of non-pointer type should have an origin list");
198 // This loan specifically tracks borrowing the variable's storage location
199 // itself and is issued to outermost origin (List->OID).
200 CurrentBlockFacts.push_back(
201 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
202 }
203}
204
206 if (isGslPointerType(CCE->getType())) {
207 handleGSLPointerConstruction(CCE);
208 return;
209 }
210 // For defaulted (implicit or `= default`) copy/move constructors, propagate
211 // origins directly. User-defined copy/move constructors are not handled here
212 // as they have opaque semantics.
214 CCE->getConstructor()->isDefaulted() && CCE->getNumArgs() == 1 &&
215 hasOrigins(CCE->getType())) {
216 const Expr *Arg = CCE->getArg(0);
217 if (OriginList *ArgList = readValue(Arg)) {
218 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
219 return;
220 }
221 }
222 // Standard library callable wrappers (e.g., std::function) propagate the
223 // stored lambda's origins.
224 if (const auto *RD = CCE->getType()->getAsCXXRecordDecl();
225 RD && isStdCallableWrapperType(RD) && CCE->getNumArgs() == 1) {
226 const Expr *Arg = CCE->getArg(0);
227 if (OriginList *ArgList = readValue(Arg)) {
228 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
229 return;
230 }
231 }
232 handleFunctionCall(CCE, /*IsGslConstruction=*/false);
233}
234
236 if (const Expr *Init = DIE->getExpr())
237 killAndFlowOrigin(*DIE, *Init);
238}
239
240void FactsGenerator::handleCXXCtorInitializer(const CXXCtorInitializer *CII) {
241 // Flows origins from the initializer expression to the field.
242 // Example: `MyObj(std::string s) : view(s) {}`
243 if (const FieldDecl *FD = CII->getAnyMember())
244 killAndFlowOrigin(*FD, *CII->getInit());
245}
246
248 // Specifically for conversion operators,
249 // like `std::string_view p = std::string{};`
250 if (isGslPointerType(MCE->getType()) &&
251 isa_and_present<CXXConversionDecl>(MCE->getCalleeDecl()) &&
253 handleFunctionCall(MCE, /*IsGslConstruction=*/true);
254 return;
255 }
256 handleFunctionCall(MCE, /*IsGslConstruction=*/false);
257}
258
260 auto *MD = ME->getMemberDecl();
261 if (isa<FieldDecl>(MD) && doesDeclHaveStorage(MD)) {
262 assert(ME->isGLValue() && "Field member should be GL value");
263 OriginList *Dst = getOriginsList(*ME);
264 assert(Dst && "Field member should have an origin list as it is GL value");
265 OriginList *Src = getOriginsList(*ME->getBase());
266 assert(Src && "Base expression should be a pointer/reference type");
267 // The field's glvalue (outermost origin) holds the same loans as the base
268 // expression.
269 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
270 Dst->getOuterOriginID(), Src->getOuterOriginID(),
271 /*Kill=*/true));
272 }
273}
274
276 handleFunctionCall(CE);
277}
278
280 const CXXNullPtrLiteralExpr *N) {
281 /// TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
282 /// pointers can use the same type of loan.
283 getOriginsList(*N);
284}
285
287 const Expr *SubExpr = CE->getSubExpr();
288 // May be null: loading an `int` has no origins but still reads the operand.
289 OriginList *Dest = getOriginsList(*CE);
290 OriginList *Src = Dest ? getOriginsList(*SubExpr) : nullptr;
291
292 switch (CE->getCastKind()) {
293 case CK_LValueToRValue:
294 // The result of an LValue-to-RValue cast on a pointer lvalue (like `q` in
295 // `int *p, *q; p = q;`) should propagate the inner origin (what the pointer
296 // points to), not the outer origin (the pointer's storage location).
297 flow(Dest, readValue(SubExpr), /*Kill=*/true);
298 return;
299 case CK_Dynamic:
300 handleAccess(SubExpr);
301 return;
302 case CK_NullToPointer:
303 // TODO: Flow into them a null origin.
304 return;
305 case CK_NoOp:
306 case CK_ConstructorConversion:
307 case CK_UserDefinedConversion:
308 flow(Dest, Src, /*Kill=*/true);
309 return;
310 case CK_UncheckedDerivedToBase:
311 case CK_DerivedToBase:
312 // It is possible that the derived class and base class have different
313 // gsl::Pointer annotations. Skip if their origin shape differ.
314 if (Dest && Src && Dest->getLength() == Src->getLength())
315 flow(Dest, Src, /*Kill=*/true);
316 return;
317 case CK_ArrayToPointerDecay:
318 // va_arg(ap, array_type) is UB and does not provide addressable array
319 // storage to model.
320 if (!Dest || isa<VAArgExpr>(SubExpr->IgnoreParens()))
321 return;
322 assert(Src && "Array expression should have origins as it is GL value");
323 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
324 Dest->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
325 return;
326 case CK_FunctionToPointerDecay:
327 case CK_BuiltinFnToFnPtr:
328 // Ignore function-to-pointer decays.
329 return;
330 case CK_BitCast:
331 // OriginLists for Src and Dst may differ here. For example when casting
332 // from int** to void*
333 if (Src && Dest && Dest->getLength() == Src->getLength())
334 flow(Dest, Src, /*Kill=*/true);
335 return;
336 case CK_LValueToRValueBitCast:
337 case CK_NonAtomicToAtomic:
338 case CK_AtomicToNonAtomic: {
339 // `__builtin_bit_cast`/`std::bit_cast` of a pointer, and
340 // wrapping/unwrapping `_Atomic(T*)`, preserve the pointer value, so
341 // propagate the borrow. readValue peels a glvalue operand's storage level
342 // and records the read. A bit-cast that materializes a pointer from a
343 // non-pointer representation has no matching source origin and is
344 // untracked.
345 OriginList *RVSrc = readValue(SubExpr);
346 if (Dest && RVSrc && Dest->getLength() == RVSrc->getLength())
347 flow(Dest, RVSrc, /*Kill=*/true);
348 return;
349 }
350 default:
351 return;
352 }
353}
354
356 switch (UO->getOpcode()) {
357 case UO_AddrOf: {
358 const Expr *SubExpr = UO->getSubExpr();
359 // Function addresses do not need lifetime tracking.
360 if (SubExpr->getType()->isFunctionType())
361 return;
362 // Skip address-of on void expressions: GNU C permits them, but void itself
363 // has no origins to track.
364 if (IsCMode && SubExpr->getType()->isVoidType())
365 return;
366 assert(!SubExpr->getType()->isVoidType() &&
367 "Taking address of void is not valid in C++");
368 // The origin of an address-of expression (e.g., &x) is the origin of
369 // its sub-expression (x). This fact will cause the dataflow analysis
370 // to propagate any loans held by the sub-expression's origin to the
371 // origin of this UnaryOperator expression.
372 killAndFlowOrigin(*UO, *SubExpr);
373 return;
374 }
375 case UO_Deref: {
376 const Expr *SubExpr = UO->getSubExpr();
377 killAndFlowOrigin(*UO, *SubExpr);
378 return;
379 }
380 case UO_Plus: {
381 // Unary plus on a pointer is the identity (`+p == p`), so the prvalue
382 // result carries the operand's loans. Flow the operand's rvalue origins
383 // (peeling storage only when the operand is itself a glvalue).
384 if (!UO->getType()->isPointerType())
385 return;
386 const Expr *SubExpr = UO->getSubExpr();
387 flow(getOriginsList(*UO), readValue(SubExpr), /*Kill=*/true);
388 return;
389 }
390 case UO_PreInc:
391 case UO_PostInc:
392 case UO_PreDec:
393 case UO_PostDec: {
394 handleAccess(UO->getSubExpr());
395 // Inc/dec keeps a pointer in the same allocation, so the result carries the
396 // operand's loans. Peel the operand's storage origin when the *result* is a
397 // prvalue (post-inc/dec, or any form in C).
398 if (!UO->getType()->isPointerType())
399 return;
400 OriginList *SubList = getOriginsList(*UO->getSubExpr());
401 flow(getOriginsList(*UO),
402 UO->isGLValue() ? SubList : SubList->peelOuterOrigin(), /*Kill=*/true);
403 return;
404 }
405 default:
406 return;
407 }
408}
409
411 if (const Expr *RetExpr = RS->getRetValue()) {
412 if (OriginList *List = getOriginsList(*RetExpr))
413 for (OriginList *L = List; L != nullptr; L = L->peelOuterOrigin())
414 EscapesInCurrentBlock.push_back(FactMgr.createFact<ReturnEscapeFact>(
415 L->getOuterOriginID(), RetExpr));
416 }
417}
418
419void FactsGenerator::handleAssignment(const Expr *TargetExpr,
420 const Expr *LHSExpr,
421 const Expr *RHSExpr) {
422 LHSExpr = LHSExpr->IgnoreParenImpCasts();
423 handleAccess(LHSExpr);
424 OriginList *RHSList = readValue(RHSExpr);
425 OriginList *LHSList = nullptr;
426
427 if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
428 LHSList = getOriginsList(*DRE_LHS);
429 assert(LHSList && "LHS is a DRE and should have an origin list");
430 }
431 // Handle assignment to member fields (e.g., `this->view = s` or `view = s`).
432 // This enables detection of dangling fields when local values escape to
433 // fields.
434 if (const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
435 LHSList = getOriginsList(*ME_LHS);
436 assert(LHSList && "LHS is a MemberExpr and should have an origin list");
437 }
438 if (!LHSList)
439 return;
440
441 if (!RHSList) {
442 // RHS has no tracked origins (e.g., assigning a callable without origins
443 // to std::function). Clear loans of the destination.
444 for (OriginList *LHSInner = LHSList->peelOuterOrigin(); LHSInner;
445 LHSInner = LHSInner->peelOuterOrigin())
446 CurrentBlockFacts.push_back(
447 FactMgr.createFact<KillOriginFact>(LHSInner->getOuterOriginID()));
448 return;
449 }
450 // Kill the old loans of the destination origin and flow the new loans
451 // from the source origin.
452 flow(LHSList->peelOuterOrigin(), RHSList, /*Kill=*/true);
453
454 // In C, assignment expressions are not GLValues, so the assignment result has
455 // the assigned value origins, not the LHS storage origin.
456 if (IsCMode)
457 LHSList = LHSList->peelOuterOrigin();
458 flow(getOriginsList(*TargetExpr), LHSList, /*Kill=*/true);
459}
460
461void FactsGenerator::handlePointerArithmetic(const BinaryOperator *BO) {
462 if (Expr *RHS = BO->getRHS(); RHS->getType()->isPointerType()) {
463 killAndFlowOrigin(*BO, *RHS);
464 return;
465 }
466 Expr *LHS = BO->getLHS();
467 assert(LHS->getType()->isPointerType() &&
468 "Pointer arithmetic must have a pointer operand");
469 killAndFlowOrigin(*BO, *LHS);
470}
471
473 if (BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI) {
474 // `obj.*pm` / `objptr->*pm` names a member of the object, so a borrow of it
475 // borrows the object; flow the object's origin into the result. For `.*`
476 // the object is the LHS; for `->*` it is the LHS pointer's pointee.
477 //
478 // Only the result's outer (storage) origin relates to the object: borrowing
479 // the member borrows the object's storage. Deeper levels of the result (a
480 // pointer/view member's own pointee) are the member's value, with no
481 // counterpart in the object's origin -- so the lists may differ in length
482 // and we flow just the top level, leaving the member's value untouched.
483 OriginList *Dst = getOriginsList(*BO);
484 OriginList *ObjSrc = BO->getOpcode() == BO_PtrMemD
485 ? getOriginsList(*BO->getLHS())
486 : readValue(BO->getLHS());
487 if (Dst && ObjSrc)
488 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
489 Dst->getOuterOriginID(), ObjSrc->getOuterOriginID(), /*Kill=*/true));
490 return;
491 }
492 if (BO->getOpcode() == BO_Comma) {
493 killAndFlowOrigin(*BO, *BO->getRHS());
494 return;
495 }
496 if (BO->isCompoundAssignmentOp()) {
497 handleAccess(BO->getLHS());
498 // A pointer compound additive assignment (`p += n`) carries the LHS's loans
499 // like inc/dec above; in C the result is a prvalue, so peel its outer
500 // (storage) origin.
501 if (BO->getType()->isPointerType()) {
502 OriginList *LHSList = getOriginsList(*BO->getLHS());
503 flow(getOriginsList(*BO), IsCMode ? LHSList->peelOuterOrigin() : LHSList,
504 /*Kill=*/true);
505 }
506 return;
507 }
508 if (BO->getType()->isPointerType() && BO->isAdditiveOp())
509 handlePointerArithmetic(BO);
510 if (BO->isAssignmentOp())
511 handleAssignment(BO, BO->getLHS(), BO->getRHS());
512 // TODO: Propagate origins for assignments through a dereference (`*p = q`).
513}
514
515static const CFGBlock *findPredBlockForExpr(const CFGBlock *MergeBlock,
516 const Expr *ArmExpr) {
517 if (!ArmExpr)
518 return nullptr;
519 const Expr *Target = ArmExpr->IgnoreParenImpCasts();
520 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Target))
521 if (const Expr *Src = OVE->getSourceExpr())
522 Target = Src->IgnoreParenImpCasts();
523
524 for (const CFGBlock *Pred : MergeBlock->preds()) {
525 if (!Pred)
526 continue;
527 for (const CFGElement &Elt : *Pred)
528 if (auto CS = Elt.getAs<CFGStmt>())
529 if (const auto *E = dyn_cast<Expr>(CS->getStmt()))
530 if (E->IgnoreParenImpCasts() == Target)
531 return Pred;
532 }
533 return nullptr;
534}
535
536/// Visits conditional operators (e.g., `cond ? a : b`).
537///
538/// To prevent liveness leakage across loop backedges (which causes false
539/// positives like in `while (...) { int x; consume(cond ? &x : nullptr); }`),
540/// we generate the flow facts in the respective predecessor blocks of the arms
541/// rather than in the merge block. This ensures that the liveness of the
542/// temporary origin from one arm does not propagate into the other arm's path.
544 const AbstractConditionalOperator *CO) {
545 if (!hasOrigins(CO))
546 return;
547
548 const Expr *TrueExpr = CO->getTrueExpr();
549 const Expr *FalseExpr = CO->getFalseExpr();
550
551 if (const CFGBlock *TBPred = findPredBlockForExpr(CurrentBlock, TrueExpr))
552 flow(getOriginsList(*CO), getOriginsList(*TrueExpr), /*Kill=*/true, TBPred);
553 if (const CFGBlock *FBPred = findPredBlockForExpr(CurrentBlock, FalseExpr))
554 flow(getOriginsList(*CO), getOriginsList(*FalseExpr), /*Kill=*/true,
555 FBPred);
556}
557
559 // Assignment operators have special "kill-then-propagate" semantics
560 // and are handled separately.
561 if (OCE->getOperator() == OO_Equal && OCE->getNumArgs() == 2 &&
562 hasOrigins(OCE->getArg(0)->getType())) {
563 // Pointer-like types: assignment inherently propagates origins.
564 QualType LHSTy = OCE->getArg(0)->getType();
565 if (LHSTy->isPointerOrReferenceType() || isGslPointerType(LHSTy) ||
566 isGslOwnerType(LHSTy)) {
567 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
568 return;
569 }
570 // Standard library callable wrappers (e.g., std::function) can propagate
571 // the stored lambda's origins.
572 if (const auto *RD = LHSTy->getAsCXXRecordDecl();
573 RD && isStdCallableWrapperType(RD)) {
574 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
575 return;
576 }
577 // Other tracked types: only defaulted operator= propagates origins.
578 // User-defined operator= has opaque semantics, so don't handle them now.
579 if (const auto *MD =
580 dyn_cast_or_null<CXXMethodDecl>(OCE->getDirectCallee());
581 MD && MD->isDefaulted()) {
582 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
583 return;
584 }
585 }
586
587 handleFunctionCall(OCE);
588}
589
591 const CXXFunctionalCastExpr *FCE) {
592 // Check if this is a test point marker. If so, we are done with this
593 // expression.
594 if (handleTestPoint(FCE))
595 return;
596 VisitCastExpr(FCE);
597}
598
600 if (!hasOrigins(ILE))
601 return;
602 // For list initialization with a single element, like `View{...}`, the
603 // origin of the list itself is the origin of its single element.
604 if (ILE->getNumInits() == 1) {
605 // A type with origins may be list-initialized from an element with none
606 // (e.g., an int). Only flow if the element carries any.
607 if (!hasOrigins(ILE->getInit(0)))
608 return;
609 killAndFlowOrigin(*ILE, *ILE->getInit(0));
610 }
611}
612
614 const CXXBindTemporaryExpr *BTE) {
615 killAndFlowOrigin(*BTE, *BTE->getSubExpr());
616}
617
619 const MaterializeTemporaryExpr *MTE) {
620 assert(MTE->isGLValue());
621 OriginList *MTEList = getOriginsList(*MTE);
622 if (!MTEList)
623 return;
624 OriginList *SubExprList = getOriginsList(*MTE->getSubExpr());
625 assert((!SubExprList ||
626 MTEList->getLength() == (SubExprList->getLength() + 1)) &&
627 "MTE top level origin should contain a loan to the MTE itself");
628
629 OriginList *RValMTEList = MTEList->peelOuterOrigin();
630 flow(RValMTEList, SubExprList, /*Kill=*/true);
631 OriginID OuterMTEID = MTEList->getOuterOriginID();
633 // Issue a loan to MTE for the storage location represented by MTE.
634 const Loan *L = createLoan(FactMgr, MTE);
635 CurrentBlockFacts.push_back(
636 FactMgr.createFact<IssueFact>(L->getID(), OuterMTEID));
637 }
638}
639
641 for (const LambdaCapture &C : LE->captures()) {
642 if (C.capturesThis())
643 FactMgr.setThisCapturedByLambda();
644 else if (C.capturesVariable() && C.getCapturedVar()->isInitCapture()) {
645 const Expr *Init = cast<VarDecl>(C.getCapturedVar())->getInit();
646 if (!Init)
647 continue;
648 if (const auto *ME = dyn_cast<MemberExpr>(Init->IgnoreParenImpCasts())) {
649 if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
650 FactMgr.addCapturedField(FD);
651 }
652 }
653 }
654
655 // The lambda gets a single merged origin that aggregates all captured
656 // pointer-like origins. Currently we only need to detect whether the lambda
657 // outlives any capture.
658 OriginList *LambdaList = getOriginsList(*LE);
659 if (!LambdaList)
660 return;
661 bool Kill = true;
662 for (const Expr *Init : LE->capture_inits()) {
663 if (!Init)
664 continue;
665 // The lambda body may dereference a capture to any depth.
666 handleUse(Init);
667 OriginList *InitList = getOriginsList(*Init);
668 if (!InitList)
669 continue;
670 // FIXME: Consider flowing all origin levels once lambdas support more than
671 // one origin. Currently only the outermost origin is flowed, so by-ref
672 // captures like `[&p]` (where p is string_view) miss inner-level
673 // invalidation.
674 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
675 LambdaList->getOuterOriginID(), InitList->getOuterOriginID(), Kill));
676 Kill = false;
677 }
678}
679
681 // Some C subscripts do not refer to addressable storage with origins, such as
682 // GNU void-pointer subscripts and vector element extraction from rvalues.
683 if (IsCMode && !ASE->isGLValue())
684 return;
685 assert(ASE->isGLValue() && "Array subscript should be a GL value");
686 OriginList *Dst = getOriginsList(*ASE);
687 assert(Dst && "Array subscript should have origins as it is a GL value");
688 OriginList *Src = getOriginsList(*ASE->getBase());
689 assert(Src && "Base of array subscript should have origins");
690 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
691 Dst->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
692}
693
694bool FactsGenerator::handlePlacementNew(const CXXNewExpr *NE,
695 OriginList *NewList) {
696 // Model only the standard single-argument placement new form, where the
697 // placement argument corresponds to a void* allocation-function parameter.
698 // Other placement forms, such as std::nothrow, are not modeled as providing
699 // storage for the returned pointer.
700 if (NE->getNumPlacementArgs() != 1)
701 return false;
702
703 const FunctionDecl *OperatorNew = NE->getOperatorNew();
704 if (OperatorNew->getNumParams() <= 1)
705 return false;
706
707 const auto *Arg =
708 OperatorNew->getParamDecl(1)->getType()->getAs<PointerType>();
709 if (!Arg || !Arg->isVoidPointerType())
710 return false;
711
712 // Use the placement argument before the implicit conversion to void*, so
713 // inner origins are still available.
714 const Expr *PlacementArg = NE->getPlacementArg(0);
715 if (const auto *ICE = dyn_cast<ImplicitCastExpr>(PlacementArg);
716 ICE && ICE->getCastKind() == CK_BitCast &&
717 PlacementArg->getType()->isVoidPointerType())
718 PlacementArg = ICE->getSubExpr();
719 OriginList *PlacementList = getOriginsList(*PlacementArg);
720 // FIXME: General placement arguments need separate handling to overwrite
721 // the right origins.
722
723 handleAccess(PlacementArg);
724
725 // The pointer returned by placement new comes from the placement
726 // argument.
727 if (PlacementList)
728 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
729 NewList->getOuterOriginID(), PlacementList->getOuterOriginID(), true));
730 return true;
731}
732
734 OriginList *NewList = getOriginsList(*NE);
735 const Expr *Init = NE->getInitializer();
736
737 bool HandledAsPlacementNew = false;
738 if (NE->getNumPlacementArgs() == 1)
739 HandledAsPlacementNew = handlePlacementNew(NE, NewList);
740
741 // Treat ordinary new and replaceable global allocation forms as heap
742 // allocations.
743 const FunctionDecl *OperatorNew = NE->getOperatorNew();
744 if (!HandledAsPlacementNew &&
745 (NE->getNumPlacementArgs() == 0 ||
746 (OperatorNew && OperatorNew->isReplaceableGlobalAllocationFunction()))) {
747 const Loan *L = createLoan(FactMgr, NE);
748 CurrentBlockFacts.push_back(
749 FactMgr.createFact<IssueFact>(L->getID(), NewList->getOuterOriginID()));
750 }
751
752 NewList = NewList->peelOuterOrigin();
753
754 if (!NewList || !Init)
755 return;
756
757 // FIXME: OriginList is null for `new[]` initializers. Remove this `Init`
758 // check once array origins are supported.
759 if (OriginList *InitList = getOriginsList(*Init); InitList)
760 flow(NewList, InitList, true);
761}
762
763// TODO: An escape fact may fit `throw` and asm better than a use.
765 if (const Expr *Sub = TE->getSubExpr())
766 handleUse(Sub);
767}
768
770 for (const Expr *Input : AS->inputs())
771 handleUse(Input);
772 for (unsigned I = 0, N = AS->getNumOutputs(); I != N; ++I)
773 if (AS->isOutputPlusConstraint(I)) // Also read.
774 handleUse(AS->getOutputExpr(I));
775 else
776 handleAccess(AS->getOutputExpr(I));
777}
778
780 if (TE->isPotentiallyEvaluated())
781 handleAccess(TE->getExprOperand());
782}
783
785 // The destructor may dereference to any depth.
786 handleUse(DE->getArgument());
787 OriginList *List = getOriginsList(*DE->getArgument());
788 CurrentBlockFacts.push_back(
789 FactMgr.createFact<InvalidateOriginFact>(List->getOuterOriginID(), DE));
790}
791
793 // A statement expression (`({ ...; e; })`) yields the value of its final
794 // expression `e`. Flow `e`'s origins into the statement expression's origin
795 // so a borrow `e` carries reaches the value's users.
796 const auto *CS = SE->getSubStmt();
797 if (!CS || CS->body_empty())
798 return;
799 const auto *Last = dyn_cast<Expr>(CS->body_back());
800 if (!Last)
801 return;
802 if (OriginList *Dst = getOriginsList(*SE))
803 if (OriginList *Src = readValue(Last))
804 flow(Dst, Src, /*Kill=*/true);
805}
806
807bool FactsGenerator::escapesViaReturn(OriginID OID) const {
808 return llvm::any_of(EscapesInCurrentBlock, [OID](const Fact *F) {
809 if (const auto *EF = F->getAs<ReturnEscapeFact>())
810 return EF->getEscapedOriginID() == OID;
811 return false;
812 });
813}
814
815void FactsGenerator::handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds) {
816 const VarDecl *LifetimeEndsVD = LifetimeEnds.getVarDecl();
817 if (!LifetimeEndsVD)
818 return;
819 // Expire the origin when its variable's lifetime ends to ensure liveness
820 // doesn't persist through loop back-edges.
821 std::optional<OriginID> ExpiredOID;
822 if (OriginList *List = getOriginsList(*LifetimeEndsVD)) {
823 OriginID OID = List->getOuterOriginID();
824 // Skip origins that escape via return; the escape checker needs their loans
825 // to remain until the return statement is processed.
826 if (!escapesViaReturn(OID))
827 ExpiredOID = OID;
828 }
829 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
830 AccessPath(LifetimeEndsVD), LifetimeEnds.getTriggerStmt()->getEndLoc(),
831 ExpiredOID));
832}
833
834void FactsGenerator::handleFullExprCleanup(
835 const CFGFullExprCleanup &FullExprCleanup) {
836 for (const auto *MTE : FullExprCleanup.getExpiringMTEs())
837 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
838 AccessPath(MTE), FullExprCleanup.getCleanupLoc()));
839}
840
841void FactsGenerator::handleExitBlock() {
842 bool IsDestructor = isa_and_nonnull<CXXDestructorDecl>(AC.getDecl());
843 for (const Origin &O : FactMgr.getOriginMgr().getOrigins())
844 // Create FieldEscapeFacts for all field origins that remain live at exit.
845 // Fields in destructors do not escape since the object is being destroyed.
846 if (auto *FD = dyn_cast_if_present<FieldDecl>(O.getDecl());
847 FD && !IsDestructor)
848 EscapesInCurrentBlock.push_back(
849 FactMgr.createFact<FieldEscapeFact>(O.ID, FD));
850 else if (auto *VD = dyn_cast_if_present<VarDecl>(O.getDecl())) {
851 // Create GlobalEscapeFacts for all origins with global-storage that
852 // remain live at exit.
853 if (VD->hasGlobalStorage()) {
854 EscapesInCurrentBlock.push_back(
855 FactMgr.createFact<GlobalEscapeFact>(O.ID, VD));
856 }
857 }
858}
859
860void FactsGenerator::handleGSLPointerConstruction(const CXXConstructExpr *CCE) {
861 assert(isGslPointerType(CCE->getType()));
862 if (CCE->getNumArgs() != 1)
863 return;
864
865 const Expr *Arg = CCE->getArg(0);
866 if (isGslPointerType(Arg->getType())) {
867 // GSL pointer is constructed from another gsl pointer.
868 // Example:
869 // View(View v);
870 // View(const View &v);
871 OriginList *ArgList = readValue(Arg);
872 assert(ArgList && "GSL pointer argument should have an origin list");
873 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
874 } else if (Arg->getType()->isPointerType()) {
875 // GSL pointer is constructed from a raw pointer. Flow only the outermost
876 // raw pointer. Example:
877 // View(const char*);
878 // Span<int*>(const in**);
879 OriginList *ArgList = getOriginsList(*Arg);
880 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
881 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
882 /*Kill=*/true));
883 } else {
884 // This could be a new borrow.
885 // TODO: Add code example here.
886 handleFunctionCall(CCE, /*IsGslConstruction=*/true);
887 }
888}
889
890void FactsGenerator::handleMovedArgsInCall(const FunctionDecl *FD,
891 ArrayRef<const Expr *> Args) {
892 unsigned ImplicitObjectArgOffset = 0;
893 // Constructors are excluded because Args has no object argument for them,
894 // even though isImplicitObjectMemberFunction() is true.
895 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD);
896 MD && !isa<CXXConstructorDecl>(FD) &&
897 MD->isImplicitObjectMemberFunction()) {
898 ImplicitObjectArgOffset = 1;
899 // std::unique_ptr::release() transfers ownership.
900 // Treat it as a move to prevent false-positive warnings when the unique_ptr
901 // destructor runs after ownership has been transferred.
902 if (isUniquePtrRelease(*MD)) {
903 const Expr *UniquePtrExpr = Args[0];
904 OriginList *MovedOrigins = getOriginsList(*UniquePtrExpr);
905 if (MovedOrigins)
906 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
907 UniquePtrExpr, MovedOrigins->getOuterOriginID()));
908 }
909 }
910
911 // Skip implicit 'this' arg as it cannot be moved.
912 for (unsigned I = ImplicitObjectArgOffset;
913 I < Args.size() && I < FD->getNumParams() + ImplicitObjectArgOffset;
914 ++I) {
915 const ParmVarDecl *PVD = FD->getParamDecl(I - ImplicitObjectArgOffset);
916 // In principle, explicit object parameters can be moved, but skip marking
917 // them as moved for consistency with implicit 'this'.
918 if (PVD->isExplicitObjectParameter())
919 continue;
920 if (!PVD->getType()->isRValueReferenceType())
921 continue;
922 // Skip lifetime annotated r-value reference parameters. Lifetime annotation
923 // indicates that the parameter is borrowed (not consumed), so it should not
924 // be marked as moved even though it's an r-value reference.
925 if (PVD->hasAttr<LifetimeBoundAttr>() ||
926 PVD->hasAttr<LifetimeCaptureByAttr>())
927 continue;
928 const Expr *Arg = Args[I];
929 OriginList *MovedOrigins = getOriginsList(*Arg);
930 assert(MovedOrigins->getLength() >= 1 &&
931 "unexpected length for r-value reference param");
932 // Arg is being moved to this parameter. Mark the origin as moved.
933 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
934 Arg, MovedOrigins->getOuterOriginID()));
935 }
936}
937
938void FactsGenerator::handleInvalidatingCall(const Expr *Call,
939 const FunctionDecl *FD,
940 ArrayRef<const Expr *> Args) {
941 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
942 if (!MD || !MD->isInstance())
943 return;
944
945 if (!isInvalidationMethod(*MD))
946 return;
947
948 // Heuristics to turn-down false positives. Skip member field expressions for
949 // now. This is not a perfect filter and will still surface some false
950 // positives (e.g. `auto& r = s.v`).
951 if (!isa<DeclRefExpr>(Args[0]->IgnoreImpCasts()))
952 return;
953
954 OriginList *ThisList = getOriginsList(*Args[0]);
955 if (ThisList)
956 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
957 ThisList->getOuterOriginID(), Call));
958}
959
960void FactsGenerator::handleDestructiveCall(const Expr *Call,
961 const FunctionDecl *FD,
962 ArrayRef<const Expr *> Args) {
963 if (!destructsFirstArg(*FD))
964 return;
965 OriginList *ArgList = getOriginsList(*Args[0]);
966 if (ArgList)
967 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
968 ArgList->getOuterOriginID(), Call));
969}
970
971void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call,
972 const FunctionDecl *FD) {
973 const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call);
974 if (!MemberCall)
975 return;
976
977 if (!isa_and_present<CXXThisExpr>(
978 MemberCall->getImplicitObjectArgument()->IgnoreImpCasts()))
979 return;
980
981 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
982 assert(MD && "Function must be a CXXMethodDecl for member calls");
983
984 const auto *ClassDecl = MD->getParent()->getDefinition();
985 if (!ClassDecl)
986 return;
987
988 const auto UseFields = [&](const CXXRecordDecl *RD) {
989 for (const auto *Field : RD->fields())
990 if (auto *FieldList = getOriginsList(*Field))
991 CurrentBlockFacts.push_back(
992 FactMgr.createFact<UseFact>(Call, FieldList));
993 };
994
995 UseFields(ClassDecl);
996
997 ClassDecl->forallBases([&](const CXXRecordDecl *Base) {
998 UseFields(Base);
999 return true;
1000 });
1001}
1002
1003void FactsGenerator::handleLifetimeCaptureBy(const FunctionDecl *FD,
1004 ArrayRef<const Expr *> Args) {
1005 if (Args.empty())
1006 return;
1007 // FIXME: Add support for capture_by on constructors.
1009 return;
1010 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
1011 bool IsInstance =
1012 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD);
1013 auto getParamDeclAt = [FD, IsInstance](unsigned I) -> const ParmVarDecl * {
1014 if (IsInstance) {
1015 // FIXME: Add support for I == 0 i.e. capture_by on function declarations
1016 if (I > 0 && I - 1 < FD->getNumParams())
1017 return FD->getParamDecl(I - 1);
1018 } else {
1019 if (I < FD->getNumParams())
1020 return FD->getParamDecl(I);
1021 }
1022 return nullptr;
1023 };
1024 for (unsigned I = 0; I < Args.size(); ++I) {
1025 const ParmVarDecl *PVD = getParamDeclAt(I);
1026 if (!PVD)
1027 continue;
1028 const auto *Attr = PVD->getAttr<LifetimeCaptureByAttr>();
1029 if (!Attr)
1030 continue;
1031 OriginList *CapturedOriginList = getOriginsList(*Args[I]);
1032 if (!CapturedOriginList)
1033 continue;
1034 // For references to pointer-like types, peel the outer origin (the pointer
1035 // object itself) so that we capture the underlying data (the inner origin).
1036 if (QualType ParamType = PVD->getType();
1037 (ParamType->isReferenceType() &&
1038 isPointerLikeType(ParamType->getPointeeType())) &&
1039 CapturedOriginList->getLength() > 1)
1040 CapturedOriginList = CapturedOriginList->peelOuterOrigin();
1041 for (int CapturingArgIdx : Attr->params()) {
1042 // FIXME: Add support for capturing to Global/unknown.
1043 if (CapturingArgIdx == LifetimeCaptureByAttr::Global ||
1044 CapturingArgIdx == LifetimeCaptureByAttr::Unknown ||
1045 CapturingArgIdx == LifetimeCaptureByAttr::Invalid)
1046 continue;
1047 ArrayRef<const Expr *> CallArgs = IsInstance ? Args.drop_front() : Args;
1048 const Expr *CapturedByArg =
1049 (CapturingArgIdx == LifetimeCaptureByAttr::This)
1050 ? Args[0]
1051 : CallArgs[CapturingArgIdx];
1052 assert(CapturedByArg && "Capturer expression must be valid");
1053
1054 OriginList *Dest = readValue(CapturedByArg);
1055 if (!Dest)
1056 continue;
1057 // KillDest=false because we cannot know if previous captures are being
1058 // replaced or accumulated. Multiple successive captures into the same
1059 // destination must all be tracked, so captured lifetimes are always
1060 // merged.
1061 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1062 Dest->getOuterOriginID(), CapturedOriginList->getOuterOriginID(),
1063 /*KillDest=*/false));
1064 }
1065 }
1066}
1067
1068void FactsGenerator::handleFunctionCall(const Expr *Call,
1069 bool IsGslConstruction) {
1070 FunctionCallInfo CallInfo(Call);
1071 llvm::ArrayRef<const Expr *> Args = CallInfo.Args;
1072 // The callee may dereference any argument to any depth.
1073 for (const Expr *Arg : Args)
1074 handleUse(Arg);
1075 if (!CallInfo.FD)
1076 return;
1077 OriginList *CallList = getOriginsList(*Call);
1078 // Ignore functions returning values with no origin.
1079 const FunctionDecl *FD = getDeclWithMergedLifetimeBoundAttrs(CallInfo.FD);
1080 if (!FD)
1081 return;
1082 handleInvalidatingCall(Call, FD, Args);
1083 handleDestructiveCall(Call, FD, Args);
1084 handleMovedArgsInCall(FD, Args);
1085 handleImplicitObjectFieldUses(Call, FD);
1086 handleLifetimeCaptureBy(FD, Args);
1087 if (!CallList)
1088 return;
1089 if (isStdReferenceCast(FD)) {
1090 assert(Args.size() == 1 &&
1091 "std reference cast builtins take exactly one argument");
1092 // std reference-cast functions like std::move return a result that refers
1093 // to the same object as the argument, so propagate the full origins.
1094 flow(CallList, getOriginsList(*Args[0]), /*Kill=*/true);
1095 return;
1096 }
1097 auto shouldTrackPointerImplicitObjectArg = [FD, &Args](unsigned I) -> bool {
1098 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
1099 if (!Method || !Method->isInstance())
1100 return false;
1101 return I == 0 &&
1102 isGslPointerType(Method->getFunctionObjectParameterType()) &&
1104 /*RunningUnderLifetimeSafety=*/true);
1105 };
1106 if (Args.empty())
1107 return;
1108 bool KillSrc = true;
1109 for (unsigned I = 0; I < Args.size(); ++I) {
1110 OriginList *ArgList = getOriginsList(*Args[I]);
1111 if (!ArgList)
1112 continue;
1113 bool ShouldTrackArg = getTrackedArgInfo(FD, Args, I).has_value();
1114 if (IsGslConstruction) {
1115 // TODO: document with code example.
1116 // std::string_view(const std::string_view& from)
1117 if (isGslPointerType(Args[I]->getType())) {
1118 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
1119 ArgList = readValue(Args[I]);
1120 }
1121 if (isGslOwnerType(Args[I]->getType())) {
1122 // The constructed gsl::Pointer borrows from the Owner's storage, not
1123 // from what the Owner itself borrows, so only the outermost origin is
1124 // needed.
1125 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1126 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
1127 KillSrc));
1128 KillSrc = false;
1129 } else if (ShouldTrackArg) {
1130 // Only flow the outer origin here. For lifetimebound args in
1131 // gsl::Pointer construction, we do not have enough information to
1132 // safely match inner origins, so the source and
1133 // destination origin lists may have different lengths.
1134 // FIXME: Handle origin-shape mismatches gracefully so we can also flow
1135 // inner origins.
1136 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1137 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
1138 KillSrc));
1139 KillSrc = false;
1140 }
1141 } else if (shouldTrackPointerImplicitObjectArg(I)) {
1142 assert(ArgList->getLength() >= 2 &&
1143 "Object arg of pointer type should have at least two origins");
1144 // See through the GSLPointer reference to see the pointer's value.
1145 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1146 CallList->getOuterOriginID(),
1147 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
1148 KillSrc = false;
1149 } else if (ShouldTrackArg) {
1150 // Lifetimebound on a non-GSL-ctor function means the returned
1151 // pointer/reference itself must not outlive the arguments. This
1152 // only constrains the top-level origin.
1153 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1154 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
1155 KillSrc = false;
1156 }
1157 }
1158}
1159
1160/// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
1161/// If so, creates a `TestPointFact` and returns true.
1162bool FactsGenerator::handleTestPoint(const CXXFunctionalCastExpr *FCE) {
1163 if (!FCE->getType()->isVoidType())
1164 return false;
1165
1166 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
1167 if (const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
1168 llvm::StringRef LiteralValue = SL->getString();
1169 const std::string Prefix = "__lifetime_test_point_";
1170
1171 if (LiteralValue.starts_with(Prefix)) {
1172 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
1173 CurrentBlockFacts.push_back(
1174 FactMgr.createFact<TestPointFact>(Annotation));
1175 return true;
1176 }
1177 }
1178 return false;
1179}
1180
1181bool FactsGenerator::namesDeclStorage(const OriginList *List) const {
1182 return FactMgr.getOriginMgr()
1183 .getOrigin(List->getOuterOriginID())
1184 .NamesDeclStorage;
1185}
1186
1187void FactsGenerator::handleAccess(const Expr *E) {
1188 OriginList *List = getOriginsList(*E);
1189 if (!List || namesDeclStorage(List))
1190 return;
1191 CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(
1192 E,
1193 FactMgr.getOriginMgr().createSingleOriginList(List->getOuterOriginID())));
1194}
1195
1196void FactsGenerator::handleUse(const Expr *E) {
1197 OriginList *List = getOriginsList(*E);
1198 if (List && namesDeclStorage(List))
1199 List = List->peelOuterOrigin();
1200 if (List)
1201 CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(E, List));
1202}
1203
1204// Creates an IssueFact for a new placeholder loan for each pointer or reference
1205// parameter at the function's entry.
1206llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
1207 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
1208 if (!FD)
1209 return {};
1210
1211 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
1212 if (auto ThisOrigins = FactMgr.getOriginMgr().getThisOrigins()) {
1213 OriginList *List = *ThisOrigins;
1214 const Loan *L =
1215 FactMgr.getLoanMgr().createPlaceholderLoan(cast<CXXMethodDecl>(FD));
1216 PlaceholderLoanFacts.push_back(
1217 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
1218 }
1219 for (const ParmVarDecl *PVD : FD->parameters()) {
1220 OriginList *List = getOriginsList(*PVD);
1221 if (!List)
1222 continue;
1223 const Loan *L = FactMgr.getLoanMgr().createPlaceholderLoan(PVD);
1224 PlaceholderLoanFacts.push_back(
1225 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
1226 }
1227 return PlaceholderLoanFacts;
1228}
1229
1230} // namespace clang::lifetimes::internal
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
TokenType getType() const
Returns the token's type, e.g.
Defines an enumeration for C++ overloaded operators.
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Definition Expr.h:4397
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4581
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4587
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition Expr.h:2765
inputs_range inputs()
Definition Stmt.h:3403
bool isOutputPlusConstraint(unsigned i) const
isOutputPlusConstraint - Return true if the specified output constraint is a "+" constraint (which is...
Definition Stmt.h:3358
unsigned getNumOutputs() const
Definition Stmt.h:3348
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4082
Expr * getLHS() const
Definition Expr.h:4132
Expr * getRHS() const
Definition Expr.h:4134
static bool isAdditiveOp(Opcode Opc)
Definition Expr.h:4168
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4218
static bool isCompoundAssignmentOp(Opcode Opc)
Definition Expr.h:4223
Opcode getOpcode() const
Definition Expr.h:4127
Represents a single basic block in a source-level CFG.
Definition CFG.h:652
pred_range preds()
Definition CFG.h:1029
Represents a top-level expression in a basic block.
Definition CFG.h:55
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
Definition CFG.h:113
Represents C++ base or member initializer from constructor's initialization list.
Definition CFG.h:232
Represents the point where the lifetime of an automatic object ends.
Definition CFG.h:321
const VarDecl * getVarDecl() const
Definition CFG.h:326
LLVM_ATTRIBUTE_RETURNS_NONNULL const Stmt * getTriggerStmt() const
Definition CFG.h:300
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1271
CFGBlock & getExit()
Definition CFG.h:1387
CFGBlock & getEntry()
Definition CFG.h:1385
Represents binding an expression to a temporary.
Definition ExprCXX.h:1497
const Expr * getSubExpr() const
Definition ExprCXX.h:1519
Represents a call to a C++ constructor.
Definition ExprCXX.h:1552
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1695
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1615
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1692
bool isCopyOrMoveConstructor(unsigned &TypeQuals) const
Determine whether this is a copy or move constructor.
Definition DeclCXX.cpp:3069
Represents a C++ base or member initializer.
Definition DeclCXX.h:2407
Expr * getInit() const
Get the initializer.
Definition DeclCXX.h:2609
FieldDecl * getAnyMember() const
Definition DeclCXX.h:2553
A use of a default initializer in a constructor or in aggregate initialization.
Definition ExprCXX.h:1381
Expr * getExpr()
Get the initialization expression that will be used.
Definition ExprCXX.cpp:1138
Represents a delete expression for memory deallocation and destructor calls, e.g.
Definition ExprCXX.h:2630
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
Definition ExprCXX.h:1835
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:183
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition ExprCXX.cpp:755
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2359
The null pointer literal (C++11 [lex.nullptr])
Definition ExprCXX.h:772
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:85
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Definition ExprCXX.h:115
A C++ throw-expression (C++ [except.throw]).
Definition ExprCXX.h:1212
const Expr * getSubExpr() const
Definition ExprCXX.h:1232
A C++ typeid expression (C++ [expr.typeid]), which gets the type_info that corresponds to the supplie...
Definition ExprCXX.h:852
Expr * getExprOperand() const
Definition ExprCXX.h:899
bool isPotentiallyEvaluated() const
Determine whether this typeid has a type operand which is potentially evaluated, per C++11 [expr....
Definition ExprCXX.cpp:135
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3191
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3170
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3178
Decl * getCalleeDecl()
Definition Expr.h:3164
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3720
CastKind getCastKind() const
Definition Expr.h:3764
Expr * getSubExpr()
Definition Expr.h:3770
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1290
NamedDecl * getFoundDecl()
Get the NamedDecl through which this reference occurred.
Definition Expr.h:1401
ValueDecl * getDecl()
Definition Expr.h:1358
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1643
decl_range decls()
Definition Stmt.h:1691
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isFunctionOrFunctionTemplate() const
Whether this declaration is a function or function template.
Definition DeclBase.h:1136
This represents one expression.
Definition Expr.h:113
bool isGLValue() const
Definition Expr.h:288
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3123
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3119
QualType getType() const
Definition Expr.h:145
Represents a member of a struct/union/class.
Definition Decl.h:3295
Represents a function declaration or definition.
Definition Decl.h:2059
bool isDefaulted() const
Whether this function is defaulted.
Definition Decl.h:2512
This represents a GCC inline-assembly statement extension.
Definition Stmt.h:3458
Expr * getOutputExpr(unsigned i)
Definition Stmt.cpp:582
Describes an C or C++ initializer list.
Definition Expr.h:5352
unsigned getNumInits() const
Definition Expr.h:5385
const Expr * getInit(unsigned Init) const
Definition Expr.h:5407
Describes the capture of a variable or of this, or of a C++1y init-capture.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Definition ExprCXX.h:1972
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4973
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Definition ExprCXX.h:4998
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition ExprCXX.h:4990
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3408
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3491
Expr * getBase() const
Definition Expr.h:3485
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3396
A (possibly-)qualified type.
Definition TypeBase.h:938
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3172
Expr * getRetValue()
Definition Stmt.h:3199
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
Definition Expr.h:4639
CompoundStmt * getSubStmt()
Definition Expr.h:4656
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition StmtVisitor.h:45
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
bool isVoidType() const
Definition TypeBase.h:9037
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isPointerType() const
Definition TypeBase.h:8665
bool isPointerOrReferenceType() const
Definition TypeBase.h:8669
bool isFunctionType() const
Definition TypeBase.h:8661
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2288
Expr * getSubExpr() const
Definition Expr.h:2329
Opcode getOpcode() const
Definition Expr.h:2324
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:713
Represents a variable declaration or definition.
Definition Decl.h:933
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
Definition Loans.h:117
FactType * createFact(Args &&...args)
Definition Facts.h:362
An abstract base class for a single, atomic lifetime-relevant event.
Definition Facts.h:40
const T * getAs() const
Definition Facts.h:82
void VisitDeclRefExpr(const DeclRefExpr *DRE)
void VisitBinaryOperator(const BinaryOperator *BO)
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE)
void VisitCXXConstructExpr(const CXXConstructExpr *CCE)
void VisitCXXTypeidExpr(const CXXTypeidExpr *TE)
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO)
Visits conditional operators (e.g., cond ?
void VisitCXXDeleteExpr(const CXXDeleteExpr *DE)
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE)
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *DIE)
void VisitInitListExpr(const InitListExpr *ILE)
void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N)
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)
void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE)
void VisitUnaryOperator(const UnaryOperator *UO)
void VisitCXXThrowExpr(const CXXThrowExpr *TE)
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE)
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE)
Represents that an origin's storage has been invalidated by a container operation (e....
Definition Facts.h:267
Loan * createLoan(AccessPath Path, const Expr *IssueExpr=nullptr)
Definition Loans.h:219
Represents a component of an access path: either a named field access or an abstract unnamed interior...
Definition Loans.h:195
A list of origins representing levels of indirection for pointer-like types.
Definition Origins.h:105
OriginList * peelOuterOrigin() const
Definition Origins.h:109
Represents that an origin escapes via a return statement.
Definition Facts.h:190
utils::ID< struct OriginTag > OriginID
Definition Origins.h:28
static const CFGBlock * findPredBlockForExpr(const CFGBlock *MergeBlock, const Expr *ArmExpr)
bool doesDeclHaveStorage(const ValueDecl *D)
Returns true if the declaration has its own storage that can be borrowed.
Definition Origins.cpp:192
static const Loan * createLoan(FactManager &FactMgr, const DeclRefExpr *DRE)
Creates a loan for the storage path of a given declaration reference.
bool isGslPointerType(QualType QT)
bool isStdCallableWrapperType(const CXXRecordDecl *RD)
bool shouldTrackImplicitObjectArg(const Expr &ImplicitObjectArgument, const CXXMethodDecl *Callee, bool RunningUnderLifetimeSafety)
bool isPointerLikeType(QualType QT)
bool isUniquePtrRelease(const CXXMethodDecl &MD)
bool isStdReferenceCast(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isInvalidationMethod(const CXXMethodDecl &MD)
bool destructsFirstArg(const FunctionDecl &FD)
bool isGslOwnerType(QualType QT)
std::optional< LifetimeBoundParamInfo > getTrackedArgInfo(const FunctionDecl *FD, llvm::ArrayRef< const Expr * > Args, unsigned I)
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ SD_FullExpression
Full-expression storage duration (for temporaries).
Definition Specifiers.h:339
U cast(CodeGen::Address addr)
Definition Address.h:327