clang 23.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}
154
155/// Simulates LValueToRValue conversion by peeling the outer lvalue origin
156/// if the expression is a GLValue. For pointer/view GLValues, this strips
157/// the origin representing the storage location to get the origins of the
158/// pointed-to value.
159///
160/// Example: For `View& v`, returns the origin of what v points to, not v's
161/// storage.
162static OriginList *getRValueOrigins(const Expr *E, OriginList *List) {
163 if (!List)
164 return nullptr;
165 return E->isGLValue() ? List->peelOuterOrigin() : List;
166}
167
169 for (const Decl *D : DS->decls())
170 if (const auto *VD = dyn_cast<VarDecl>(D))
171 if (const Expr *InitExpr = VD->getInit()) {
172 OriginList *VDList = getOriginsList(*VD);
173 if (!VDList)
174 continue;
175 OriginList *InitList = getOriginsList(*InitExpr);
176 assert(InitList && "VarDecl had origins but InitExpr did not");
177 flow(VDList, InitList, /*Kill=*/true);
178 }
179}
180
182 // Skip function references as their lifetimes are not interesting. Skip non
183 // GLValues (like EnumConstants).
184 if (DRE->getFoundDecl()->isFunctionOrFunctionTemplate() || !DRE->isGLValue())
185 return;
186 handleUse(DRE);
187 // For all declarations with storage (non-references), we issue a loan
188 // representing the borrow of the variable's storage itself.
189 //
190 // Examples:
191 // - `int x; x` issues loan to x's storage
192 // - `int* p; p` issues loan to p's storage (the pointer variable)
193 // - `View v; v` issues loan to v's storage (the view object)
194 // - `int& r = x; r` issues no loan (r has no storage, it's an alias to x)
195 if (doesDeclHaveStorage(DRE->getDecl())) {
196 const Loan *L = createLoan(FactMgr, DRE);
197 assert(L);
198 OriginList *List = getOriginsList(*DRE);
199 assert(List &&
200 "gl-value DRE of non-pointer type should have an origin list");
201 // This loan specifically tracks borrowing the variable's storage location
202 // itself and is issued to outermost origin (List->OID).
203 CurrentBlockFacts.push_back(
204 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
205 }
206}
207
209 if (isGslPointerType(CCE->getType())) {
210 handleGSLPointerConstruction(CCE);
211 return;
212 }
213 // For defaulted (implicit or `= default`) copy/move constructors, propagate
214 // origins directly. User-defined copy/move constructors are not handled here
215 // as they have opaque semantics.
217 CCE->getConstructor()->isDefaulted() && CCE->getNumArgs() == 1 &&
218 hasOrigins(CCE->getType())) {
219 const Expr *Arg = CCE->getArg(0);
220 if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
221 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
222 return;
223 }
224 }
225 // Standard library callable wrappers (e.g., std::function) propagate the
226 // stored lambda's origins.
227 if (const auto *RD = CCE->getType()->getAsCXXRecordDecl();
228 RD && isStdCallableWrapperType(RD) && CCE->getNumArgs() == 1) {
229 const Expr *Arg = CCE->getArg(0);
230 if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
231 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
232 return;
233 }
234 }
235 handleFunctionCall(CCE, CCE->getConstructor(),
236 {CCE->getArgs(), CCE->getNumArgs()},
237 /*IsGslConstruction=*/false);
238}
239
241 if (const Expr *Init = DIE->getExpr())
242 killAndFlowOrigin(*DIE, *Init);
243}
244
245void FactsGenerator::handleCXXCtorInitializer(const CXXCtorInitializer *CII) {
246 // Flows origins from the initializer expression to the field.
247 // Example: `MyObj(std::string s) : view(s) {}`
248 if (const FieldDecl *FD = CII->getAnyMember())
249 killAndFlowOrigin(*FD, *CII->getInit());
250}
251
253 // Specifically for conversion operators,
254 // like `std::string_view p = std::string{};`
255 if (isGslPointerType(MCE->getType()) &&
256 isa_and_present<CXXConversionDecl>(MCE->getCalleeDecl()) &&
258 // The argument is the implicit object itself.
259 handleFunctionCall(MCE, MCE->getMethodDecl(),
260 {MCE->getImplicitObjectArgument()},
261 /*IsGslConstruction=*/true);
262 return;
263 }
264 if (const CXXMethodDecl *Method = MCE->getMethodDecl()) {
265 // Construct the argument list, with the implicit 'this' object as the
266 // first argument.
268 Args.push_back(MCE->getImplicitObjectArgument());
269 Args.append(MCE->getArgs(), MCE->getArgs() + MCE->getNumArgs());
270
271 handleFunctionCall(MCE, Method, Args, /*IsGslConstruction=*/false);
272 }
273}
274
276 auto *MD = ME->getMemberDecl();
277 if (isa<FieldDecl>(MD) && doesDeclHaveStorage(MD)) {
278 assert(ME->isGLValue() && "Field member should be GL value");
279 OriginList *Dst = getOriginsList(*ME);
280 assert(Dst && "Field member should have an origin list as it is GL value");
281 OriginList *Src = getOriginsList(*ME->getBase());
282 assert(Src && "Base expression should be a pointer/reference type");
283 // The field's glvalue (outermost origin) holds the same loans as the base
284 // expression.
285 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
286 Dst->getOuterOriginID(), Src->getOuterOriginID(),
287 /*Kill=*/true));
288 }
289}
290
292 handleFunctionCall(CE, CE->getDirectCallee(),
293 {CE->getArgs(), CE->getNumArgs()});
294}
295
297 const CXXNullPtrLiteralExpr *N) {
298 /// TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
299 /// pointers can use the same type of loan.
300 getOriginsList(*N);
301}
302
304 OriginList *Dest = getOriginsList(*CE);
305 if (!Dest)
306 return;
307 const Expr *SubExpr = CE->getSubExpr();
308 OriginList *Src = getOriginsList(*SubExpr);
309
310 switch (CE->getCastKind()) {
311 case CK_LValueToRValue:
312 if (!SubExpr->isGLValue())
313 return;
314
315 assert(Src && "LValue being cast to RValue has no origin list");
316 // The result of an LValue-to-RValue cast on a pointer lvalue (like `q` in
317 // `int *p, *q; p = q;`) should propagate the inner origin (what the pointer
318 // points to), not the outer origin (the pointer's storage location). Strip
319 // the outer lvalue origin.
320 flow(getOriginsList(*CE), getRValueOrigins(SubExpr, Src),
321 /*Kill=*/true);
322 return;
323 case CK_NullToPointer:
324 getOriginsList(*CE);
325 // TODO: Flow into them a null origin.
326 return;
327 case CK_NoOp:
328 case CK_ConstructorConversion:
329 case CK_UserDefinedConversion:
330 flow(Dest, Src, /*Kill=*/true);
331 return;
332 case CK_UncheckedDerivedToBase:
333 case CK_DerivedToBase:
334 // It is possible that the derived class and base class have different
335 // gsl::Pointer annotations. Skip if their origin shape differ.
336 if (Dest && Src && Dest->getLength() == Src->getLength())
337 flow(Dest, Src, /*Kill=*/true);
338 return;
339 case CK_ArrayToPointerDecay:
340 // va_arg(ap, array_type) is UB and does not provide addressable array
341 // storage to model.
342 if (isa<VAArgExpr>(SubExpr->IgnoreParens()))
343 return;
344 assert(Src && "Array expression should have origins as it is GL value");
345 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
346 Dest->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
347 return;
348 case CK_FunctionToPointerDecay:
349 case CK_BuiltinFnToFnPtr:
350 // Ignore function-to-pointer decays.
351 return;
352 case CK_BitCast:
353 // OriginLists for Src and Dst may differ here. For example when casting
354 // from int** to void*
355 if (Src && Dest && Dest->getLength() == Src->getLength())
356 flow(Dest, Src, /*Kill=*/true);
357 return;
358 case CK_LValueToRValueBitCast:
359 case CK_NonAtomicToAtomic:
360 case CK_AtomicToNonAtomic: {
361 // `__builtin_bit_cast`/`std::bit_cast` of a pointer, and
362 // wrapping/unwrapping `_Atomic(T*)`, preserve the pointer value, so
363 // propagate the borrow. The operand may be a glvalue, so strip its outer
364 // lvalue level first. A bit-cast that materializes a pointer from a
365 // non-pointer representation has no matching source origin and is
366 // untracked.
367 OriginList *RVSrc = getRValueOrigins(SubExpr, Src);
368 if (RVSrc && Dest->getLength() == RVSrc->getLength())
369 flow(Dest, RVSrc, /*Kill=*/true);
370 return;
371 }
372 default:
373 return;
374 }
375}
376
378 switch (UO->getOpcode()) {
379 case UO_AddrOf: {
380 const Expr *SubExpr = UO->getSubExpr();
381 // Function addresses do not need lifetime tracking.
382 if (SubExpr->getType()->isFunctionType())
383 return;
384 // Skip address-of on void expressions: GNU C permits them, but void itself
385 // has no origins to track.
386 if (IsCMode && SubExpr->getType()->isVoidType())
387 return;
388 assert(!SubExpr->getType()->isVoidType() &&
389 "Taking address of void is not valid in C++");
390 // The origin of an address-of expression (e.g., &x) is the origin of
391 // its sub-expression (x). This fact will cause the dataflow analysis
392 // to propagate any loans held by the sub-expression's origin to the
393 // origin of this UnaryOperator expression.
394 killAndFlowOrigin(*UO, *SubExpr);
395 return;
396 }
397 case UO_Deref: {
398 const Expr *SubExpr = UO->getSubExpr();
399 killAndFlowOrigin(*UO, *SubExpr);
400 return;
401 }
402 case UO_Plus: {
403 // Unary plus on a pointer is the identity (`+p == p`), so the prvalue
404 // result carries the operand's loans. Flow the operand's rvalue origins
405 // (peeling storage only when the operand is itself a glvalue).
406 if (!UO->getType()->isPointerType())
407 return;
408 const Expr *SubExpr = UO->getSubExpr();
409 flow(getOriginsList(*UO),
410 getRValueOrigins(SubExpr, getOriginsList(*SubExpr)), /*Kill=*/true);
411 return;
412 }
413 case UO_PreInc:
414 case UO_PostInc:
415 case UO_PreDec:
416 case UO_PostDec: {
417 // Inc/dec keeps a pointer in the same allocation, so the result carries the
418 // operand's loans. Peel the operand's storage origin when the *result* is a
419 // prvalue (post-inc/dec, or any form in C) -- the inverse of
420 // getRValueOrigins, which peels when its own argument is a glvalue.
421 if (!UO->getType()->isPointerType())
422 return;
423 OriginList *SubList = getOriginsList(*UO->getSubExpr());
424 flow(getOriginsList(*UO),
425 UO->isGLValue() ? SubList : SubList->peelOuterOrigin(), /*Kill=*/true);
426 return;
427 }
428 default:
429 return;
430 }
431}
432
434 if (const Expr *RetExpr = RS->getRetValue()) {
435 if (OriginList *List = getOriginsList(*RetExpr))
436 for (OriginList *L = List; L != nullptr; L = L->peelOuterOrigin())
437 EscapesInCurrentBlock.push_back(FactMgr.createFact<ReturnEscapeFact>(
438 L->getOuterOriginID(), RetExpr));
439 }
440}
441
442void FactsGenerator::handleAssignment(const Expr *TargetExpr,
443 const Expr *LHSExpr,
444 const Expr *RHSExpr) {
445 LHSExpr = LHSExpr->IgnoreParenImpCasts();
446 OriginList *LHSList = nullptr;
447
448 if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
449 LHSList = getOriginsList(*DRE_LHS);
450 assert(LHSList && "LHS is a DRE and should have an origin list");
451 }
452 // Handle assignment to member fields (e.g., `this->view = s` or `view = s`).
453 // This enables detection of dangling fields when local values escape to
454 // fields.
455 if (const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
456 LHSList = getOriginsList(*ME_LHS);
457 assert(LHSList && "LHS is a MemberExpr and should have an origin list");
458 }
459 if (!LHSList)
460 return;
461 OriginList *RHSList = getOriginsList(*RHSExpr);
462 // For operator= with reference parameters (e.g.,
463 // `View& operator=(const View&)`), the RHS argument stays an lvalue,
464 // unlike built-in assignment where LValueToRValue cast strips the outer
465 // lvalue origin. Strip it manually to get the actual value origins being
466 // assigned.
467 RHSList = getRValueOrigins(RHSExpr, RHSList);
468
469 if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
470 QualType QT = DRE_LHS->getDecl()->getType();
471 if (QT->isReferenceType()) {
472 if (hasOrigins(QT->getPointeeType())) {
473 // Writing through a reference uses the binding but overwrites the
474 // pointee. Model this as a Read of the outer origin (keeping the
475 // binding live) and a Write of the inner origins (killing the pointee's
476 // liveness).
477 if (UseFact *UF = UseFacts.lookup(DRE_LHS)) {
478 const OriginList *FullList = UF->getUsedOrigins();
479 assert(FullList);
480 UF->setUsedOrigins(FactMgr.getOriginMgr().createSingleOriginList(
481 FullList->getOuterOriginID()));
482 if (const OriginList *InnerList = FullList->peelOuterOrigin()) {
483 UseFact *WriteUF = FactMgr.createFact<UseFact>(DRE_LHS, InnerList);
484 WriteUF->markAsWritten();
485 CurrentBlockFacts.push_back(WriteUF);
486 }
487 }
488 }
489 } else
490 markUseAsWrite(DRE_LHS);
491 }
492 if (!RHSList) {
493 // RHS has no tracked origins (e.g., assigning a callable without origins
494 // to std::function). Clear loans of the destination.
495 for (OriginList *LHSInner = LHSList->peelOuterOrigin(); LHSInner;
496 LHSInner = LHSInner->peelOuterOrigin())
497 CurrentBlockFacts.push_back(
498 FactMgr.createFact<KillOriginFact>(LHSInner->getOuterOriginID()));
499 return;
500 }
501 // Kill the old loans of the destination origin and flow the new loans
502 // from the source origin.
503 flow(LHSList->peelOuterOrigin(), RHSList, /*Kill=*/true);
504
505 // In C, assignment expressions are not GLValues, so the assignment result has
506 // the assigned value origins, not the LHS storage origin.
507 if (IsCMode)
508 LHSList = getRValueOrigins(LHSExpr, LHSList);
509 flow(getOriginsList(*TargetExpr), LHSList, /*Kill=*/true);
510}
511
512void FactsGenerator::handlePointerArithmetic(const BinaryOperator *BO) {
513 if (Expr *RHS = BO->getRHS(); RHS->getType()->isPointerType()) {
514 killAndFlowOrigin(*BO, *RHS);
515 return;
516 }
517 Expr *LHS = BO->getLHS();
518 assert(LHS->getType()->isPointerType() &&
519 "Pointer arithmetic must have a pointer operand");
520 killAndFlowOrigin(*BO, *LHS);
521}
522
524 if (BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI) {
525 // `obj.*pm` / `objptr->*pm` names a member of the object, so a borrow of it
526 // borrows the object; flow the object's origin into the result. For `.*`
527 // the object is the LHS; for `->*` it is the LHS pointer's pointee.
528 //
529 // Only the result's outer (storage) origin relates to the object: borrowing
530 // the member borrows the object's storage. Deeper levels of the result (a
531 // pointer/view member's own pointee) are the member's value, with no
532 // counterpart in the object's origin -- so the lists may differ in length
533 // and we flow just the top level, leaving the member's value untouched.
534 OriginList *Dst = getOriginsList(*BO);
535 OriginList *ObjSrc =
536 BO->getOpcode() == BO_PtrMemD
537 ? getOriginsList(*BO->getLHS())
538 : getRValueOrigins(BO->getLHS(), getOriginsList(*BO->getLHS()));
539 if (Dst && ObjSrc)
540 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
541 Dst->getOuterOriginID(), ObjSrc->getOuterOriginID(), /*Kill=*/true));
542 handleUse(BO->getLHS());
543 return;
544 }
545 if (BO->getOpcode() == BO_Comma) {
546 killAndFlowOrigin(*BO, *BO->getRHS());
547 return;
548 }
549 if (BO->isCompoundAssignmentOp()) {
550 // A pointer compound additive assignment (`p += n`) carries the LHS's loans
551 // like inc/dec above; in C the result is a prvalue, so peel its outer
552 // (storage) origin.
553 if (BO->getType()->isPointerType()) {
554 OriginList *LHSList = getOriginsList(*BO->getLHS());
555 flow(getOriginsList(*BO), IsCMode ? LHSList->peelOuterOrigin() : LHSList,
556 /*Kill=*/true);
557 }
558 return;
559 }
560 if (BO->getType()->isPointerType() && BO->isAdditiveOp())
561 handlePointerArithmetic(BO);
562 handleUse(BO->getRHS());
563 if (BO->isAssignmentOp())
564 handleAssignment(BO, BO->getLHS(), BO->getRHS());
565 // TODO: Handle assignments involving dereference like `*p = q`.
566}
567
568static const CFGBlock *findPredBlockForExpr(const CFGBlock *MergeBlock,
569 const Expr *ArmExpr) {
570 if (!ArmExpr)
571 return nullptr;
572 const Expr *Target = ArmExpr->IgnoreParenImpCasts();
573 if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Target))
574 if (const Expr *Src = OVE->getSourceExpr())
575 Target = Src->IgnoreParenImpCasts();
576
577 for (const CFGBlock *Pred : MergeBlock->preds()) {
578 if (!Pred)
579 continue;
580 for (const CFGElement &Elt : *Pred)
581 if (auto CS = Elt.getAs<CFGStmt>())
582 if (const auto *E = dyn_cast<Expr>(CS->getStmt()))
583 if (E->IgnoreParenImpCasts() == Target)
584 return Pred;
585 }
586 return nullptr;
587}
588
589/// Visits conditional operators (e.g., `cond ? a : b`).
590///
591/// To prevent liveness leakage across loop backedges (which causes false
592/// positives like in `while (...) { int x; consume(cond ? &x : nullptr); }`),
593/// we generate the flow facts in the respective predecessor blocks of the arms
594/// rather than in the merge block. This ensures that the liveness of the
595/// temporary origin from one arm does not propagate into the other arm's path.
597 const AbstractConditionalOperator *CO) {
598 if (!hasOrigins(CO))
599 return;
600
601 const Expr *TrueExpr = CO->getTrueExpr();
602 const Expr *FalseExpr = CO->getFalseExpr();
603
604 if (const CFGBlock *TBPred = findPredBlockForExpr(CurrentBlock, TrueExpr))
605 flow(getOriginsList(*CO), getOriginsList(*TrueExpr), /*Kill=*/true, TBPred);
606 if (const CFGBlock *FBPred = findPredBlockForExpr(CurrentBlock, FalseExpr))
607 flow(getOriginsList(*CO), getOriginsList(*FalseExpr), /*Kill=*/true,
608 FBPred);
609}
610
612 // Assignment operators have special "kill-then-propagate" semantics
613 // and are handled separately.
614 if (OCE->getOperator() == OO_Equal && OCE->getNumArgs() == 2 &&
615 hasOrigins(OCE->getArg(0)->getType())) {
616 // Pointer-like types: assignment inherently propagates origins.
617 QualType LHSTy = OCE->getArg(0)->getType();
618 if (LHSTy->isPointerOrReferenceType() || isGslPointerType(LHSTy) ||
619 isGslOwnerType(LHSTy)) {
620 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
621 return;
622 }
623 // Standard library callable wrappers (e.g., std::function) can propagate
624 // the stored lambda's origins.
625 if (const auto *RD = LHSTy->getAsCXXRecordDecl();
626 RD && isStdCallableWrapperType(RD)) {
627 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
628 return;
629 }
630 // Other tracked types: only defaulted operator= propagates origins.
631 // User-defined operator= has opaque semantics, so don't handle them now.
632 if (const auto *MD =
633 dyn_cast_or_null<CXXMethodDecl>(OCE->getDirectCallee());
634 MD && MD->isDefaulted()) {
635 handleAssignment(OCE, OCE->getArg(0), OCE->getArg(1));
636 return;
637 }
638 }
639
640 ArrayRef<const Expr *> Args(OCE->getArgs(), OCE->getNumArgs());
641 // For `static operator()`, the first argument is the object argument,
642 // remove it from the argument list to avoid off-by-one errors.
643 if (OCE->getOperator() == OO_Call && OCE->getDirectCallee()->isStatic())
644 Args = Args.slice(1);
645 handleFunctionCall(OCE, OCE->getDirectCallee(), Args);
646}
647
649 const CXXFunctionalCastExpr *FCE) {
650 // Check if this is a test point marker. If so, we are done with this
651 // expression.
652 if (handleTestPoint(FCE))
653 return;
654 VisitCastExpr(FCE);
655}
656
658 if (!hasOrigins(ILE))
659 return;
660 // For list initialization with a single element, like `View{...}`, the
661 // origin of the list itself is the origin of its single element.
662 if (ILE->getNumInits() == 1) {
663 // A type with origins may be list-initialized from an element with none
664 // (e.g., an int). Only flow if the element carries any.
665 if (!hasOrigins(ILE->getInit(0)))
666 return;
667 killAndFlowOrigin(*ILE, *ILE->getInit(0));
668 }
669}
670
672 const CXXBindTemporaryExpr *BTE) {
673 killAndFlowOrigin(*BTE, *BTE->getSubExpr());
674}
675
677 const MaterializeTemporaryExpr *MTE) {
678 assert(MTE->isGLValue());
679 OriginList *MTEList = getOriginsList(*MTE);
680 if (!MTEList)
681 return;
682 OriginList *SubExprList = getOriginsList(*MTE->getSubExpr());
683 assert((!SubExprList ||
684 MTEList->getLength() == (SubExprList->getLength() + 1)) &&
685 "MTE top level origin should contain a loan to the MTE itself");
686
687 OriginList *RValMTEList = getRValueOrigins(MTE, MTEList);
688 flow(RValMTEList, SubExprList, /*Kill=*/true);
689 OriginID OuterMTEID = MTEList->getOuterOriginID();
691 // Issue a loan to MTE for the storage location represented by MTE.
692 const Loan *L = createLoan(FactMgr, MTE);
693 CurrentBlockFacts.push_back(
694 FactMgr.createFact<IssueFact>(L->getID(), OuterMTEID));
695 }
696}
697
699 // The lambda gets a single merged origin that aggregates all captured
700 // pointer-like origins. Currently we only need to detect whether the lambda
701 // outlives any capture.
702 OriginList *LambdaList = getOriginsList(*LE);
703 if (!LambdaList)
704 return;
705 bool Kill = true;
706 for (const Expr *Init : LE->capture_inits()) {
707 if (!Init)
708 continue;
709 OriginList *InitList = getOriginsList(*Init);
710 if (!InitList)
711 continue;
712 // FIXME: Consider flowing all origin levels once lambdas support more than
713 // one origin. Currently only the outermost origin is flowed, so by-ref
714 // captures like `[&p]` (where p is string_view) miss inner-level
715 // invalidation.
716 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
717 LambdaList->getOuterOriginID(), InitList->getOuterOriginID(), Kill));
718 Kill = false;
719 }
720}
721
723 // Some C subscripts do not refer to addressable storage with origins, such as
724 // GNU void-pointer subscripts and vector element extraction from rvalues.
725 if (IsCMode && !ASE->isGLValue())
726 return;
727 assert(ASE->isGLValue() && "Array subscript should be a GL value");
728 OriginList *Dst = getOriginsList(*ASE);
729 assert(Dst && "Array subscript should have origins as it is a GL value");
730 OriginList *Src = getOriginsList(*ASE->getBase());
731 assert(Src && "Base of array subscript should have origins");
732 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
733 Dst->getOuterOriginID(), Src->getOuterOriginID(), /*Kill=*/true));
734}
735
736bool FactsGenerator::handlePlacementNew(const CXXNewExpr *NE,
737 OriginList *NewList) {
738 // Model only the standard single-argument placement new form, where the
739 // placement argument corresponds to a void* allocation-function parameter.
740 // Other placement forms, such as std::nothrow, are not modeled as providing
741 // storage for the returned pointer.
742 if (NE->getNumPlacementArgs() != 1)
743 return false;
744
745 const FunctionDecl *OperatorNew = NE->getOperatorNew();
746 if (OperatorNew->getNumParams() <= 1)
747 return false;
748
749 const auto *Arg =
750 OperatorNew->getParamDecl(1)->getType()->getAs<PointerType>();
751 if (!Arg || !Arg->isVoidPointerType())
752 return false;
753
754 // Use the placement argument before the implicit conversion to void*, so
755 // inner origins are still available.
756 const Expr *PlacementArg = NE->getPlacementArg(0);
757 if (const auto *ICE = dyn_cast<ImplicitCastExpr>(PlacementArg);
758 ICE && ICE->getCastKind() == CK_BitCast &&
759 PlacementArg->getType()->isVoidPointerType())
760 PlacementArg = ICE->getSubExpr();
761 OriginList *PlacementList = getOriginsList(*PlacementArg);
762 // FIXME: General placement arguments need separate handling to overwrite
763 // the right origins.
764
765 // The pointer returned by placement new comes from the placement
766 // argument.
767 if (PlacementList)
768 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
769 NewList->getOuterOriginID(), PlacementList->getOuterOriginID(), true));
770 return true;
771}
772
774 OriginList *NewList = getOriginsList(*NE);
775 const Expr *Init = NE->getInitializer();
776
777 bool HandledAsPlacementNew = false;
778 if (NE->getNumPlacementArgs() == 1)
779 HandledAsPlacementNew = handlePlacementNew(NE, NewList);
780
781 // Treat ordinary new and replaceable global allocation forms as heap
782 // allocations.
783 const FunctionDecl *OperatorNew = NE->getOperatorNew();
784 if (!HandledAsPlacementNew &&
785 (NE->getNumPlacementArgs() == 0 ||
786 (OperatorNew && OperatorNew->isReplaceableGlobalAllocationFunction()))) {
787 const Loan *L = createLoan(FactMgr, NE);
788 CurrentBlockFacts.push_back(
789 FactMgr.createFact<IssueFact>(L->getID(), NewList->getOuterOriginID()));
790 }
791
792 NewList = NewList->peelOuterOrigin();
793
794 if (!NewList || !Init)
795 return;
796
797 // FIXME: OriginList is null for `new[]` initializers. Remove this `Init`
798 // check once array origins are supported.
799 if (OriginList *InitList = getOriginsList(*Init); InitList)
800 flow(NewList, InitList, true);
801}
802
804 OriginList *List = getOriginsList(*DE->getArgument());
805 CurrentBlockFacts.push_back(
806 FactMgr.createFact<InvalidateOriginFact>(List->getOuterOriginID(), DE));
807}
808
810 // A statement expression (`({ ...; e; })`) yields the value of its final
811 // expression `e`. Flow `e`'s origins into the statement expression's origin
812 // so a borrow `e` carries reaches the value's users.
813 const auto *CS = SE->getSubStmt();
814 if (!CS || CS->body_empty())
815 return;
816 const auto *Last = dyn_cast<Expr>(CS->body_back());
817 if (!Last)
818 return;
819 if (OriginList *Dst = getOriginsList(*SE))
820 if (OriginList *Src = getRValueOrigins(Last, getOriginsList(*Last)))
821 flow(Dst, Src, /*Kill=*/true);
822}
823
824bool FactsGenerator::escapesViaReturn(OriginID OID) const {
825 return llvm::any_of(EscapesInCurrentBlock, [OID](const Fact *F) {
826 if (const auto *EF = F->getAs<ReturnEscapeFact>())
827 return EF->getEscapedOriginID() == OID;
828 return false;
829 });
830}
831
832void FactsGenerator::handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds) {
833 const VarDecl *LifetimeEndsVD = LifetimeEnds.getVarDecl();
834 if (!LifetimeEndsVD)
835 return;
836 // Expire the origin when its variable's lifetime ends to ensure liveness
837 // doesn't persist through loop back-edges.
838 std::optional<OriginID> ExpiredOID;
839 if (OriginList *List = getOriginsList(*LifetimeEndsVD)) {
840 OriginID OID = List->getOuterOriginID();
841 // Skip origins that escape via return; the escape checker needs their loans
842 // to remain until the return statement is processed.
843 if (!escapesViaReturn(OID))
844 ExpiredOID = OID;
845 }
846 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
847 AccessPath(LifetimeEndsVD), LifetimeEnds.getTriggerStmt()->getEndLoc(),
848 ExpiredOID));
849}
850
851void FactsGenerator::handleFullExprCleanup(
852 const CFGFullExprCleanup &FullExprCleanup) {
853 for (const auto *MTE : FullExprCleanup.getExpiringMTEs())
854 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
855 AccessPath(MTE), FullExprCleanup.getCleanupLoc()));
856}
857
858void FactsGenerator::handleExitBlock() {
859 for (const Origin &O : FactMgr.getOriginMgr().getOrigins())
860 if (auto *FD = dyn_cast_if_present<FieldDecl>(O.getDecl()))
861 // Create FieldEscapeFacts for all field origins that remain live at exit.
862 EscapesInCurrentBlock.push_back(
863 FactMgr.createFact<FieldEscapeFact>(O.ID, FD));
864 else if (auto *VD = dyn_cast_if_present<VarDecl>(O.getDecl())) {
865 // Create GlobalEscapeFacts for all origins with global-storage that
866 // remain live at exit.
867 if (VD->hasGlobalStorage()) {
868 EscapesInCurrentBlock.push_back(
869 FactMgr.createFact<GlobalEscapeFact>(O.ID, VD));
870 }
871 }
872}
873
874void FactsGenerator::handleGSLPointerConstruction(const CXXConstructExpr *CCE) {
875 assert(isGslPointerType(CCE->getType()));
876 if (CCE->getNumArgs() != 1)
877 return;
878
879 const Expr *Arg = CCE->getArg(0);
880 if (isGslPointerType(Arg->getType())) {
881 OriginList *ArgList = getOriginsList(*Arg);
882 assert(ArgList && "GSL pointer argument should have an origin list");
883 // GSL pointer is constructed from another gsl pointer.
884 // Example:
885 // View(View v);
886 // View(const View &v);
887 ArgList = getRValueOrigins(Arg, ArgList);
888 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
889 } else if (Arg->getType()->isPointerType()) {
890 // GSL pointer is constructed from a raw pointer. Flow only the outermost
891 // raw pointer. Example:
892 // View(const char*);
893 // Span<int*>(const in**);
894 OriginList *ArgList = getOriginsList(*Arg);
895 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
896 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
897 /*Kill=*/true));
898 } else {
899 // This could be a new borrow.
900 // TODO: Add code example here.
901 handleFunctionCall(CCE, CCE->getConstructor(),
902 {CCE->getArgs(), CCE->getNumArgs()},
903 /*IsGslConstruction=*/true);
904 }
905}
906
907void FactsGenerator::handleMovedArgsInCall(const FunctionDecl *FD,
908 ArrayRef<const Expr *> Args) {
909 unsigned IsInstance = 0;
910 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD);
911 MD && MD->isInstance() && !isa<CXXConstructorDecl>(FD)) {
912 IsInstance = 1;
913 // std::unique_ptr::release() transfers ownership.
914 // Treat it as a move to prevent false-positive warnings when the unique_ptr
915 // destructor runs after ownership has been transferred.
916 if (isUniquePtrRelease(*MD)) {
917 const Expr *UniquePtrExpr = Args[0];
918 OriginList *MovedOrigins = getOriginsList(*UniquePtrExpr);
919 if (MovedOrigins)
920 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
921 UniquePtrExpr, MovedOrigins->getOuterOriginID()));
922 }
923 }
924
925 // Skip 'this' arg as it cannot be moved.
926 for (unsigned I = IsInstance;
927 I < Args.size() && I < FD->getNumParams() + IsInstance; ++I) {
928 const ParmVarDecl *PVD = FD->getParamDecl(I - IsInstance);
929 if (!PVD->getType()->isRValueReferenceType())
930 continue;
931 // Skip lifetime annotated r-value reference parameters. Lifetime annotation
932 // indicates that the parameter is borrowed (not consumed), so it should not
933 // be marked as moved even though it's an r-value reference.
934 if (PVD->hasAttr<LifetimeBoundAttr>() ||
935 PVD->hasAttr<LifetimeCaptureByAttr>())
936 continue;
937 const Expr *Arg = Args[I];
938 OriginList *MovedOrigins = getOriginsList(*Arg);
939 assert(MovedOrigins->getLength() >= 1 &&
940 "unexpected length for r-value reference param");
941 // Arg is being moved to this parameter. Mark the origin as moved.
942 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
943 Arg, MovedOrigins->getOuterOriginID()));
944 }
945}
946
947void FactsGenerator::handleInvalidatingCall(const Expr *Call,
948 const FunctionDecl *FD,
949 ArrayRef<const Expr *> Args) {
950 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
951 if (!MD || !MD->isInstance())
952 return;
953
954 if (!isInvalidationMethod(*MD))
955 return;
956
957 // Heuristics to turn-down false positives. Skip member field expressions for
958 // now. This is not a perfect filter and will still surface some false
959 // positives (e.g. `auto& r = s.v`).
960 if (!isa<DeclRefExpr>(Args[0]->IgnoreImpCasts()))
961 return;
962
963 OriginList *ThisList = getOriginsList(*Args[0]);
964 if (ThisList)
965 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
966 ThisList->getOuterOriginID(), Call));
967}
968
969void FactsGenerator::handleDestructiveCall(const Expr *Call,
970 const FunctionDecl *FD,
971 ArrayRef<const Expr *> Args) {
972 if (!destructsFirstArg(*FD))
973 return;
974 OriginList *ArgList = getOriginsList(*Args[0]);
975 if (ArgList)
976 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
977 ArgList->getOuterOriginID(), Call));
978}
979
980void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call,
981 const FunctionDecl *FD) {
982 const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call);
983 if (!MemberCall)
984 return;
985
986 if (!isa_and_present<CXXThisExpr>(
987 MemberCall->getImplicitObjectArgument()->IgnoreImpCasts()))
988 return;
989
990 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
991 assert(MD && "Function must be a CXXMethodDecl for member calls");
992
993 const auto *ClassDecl = MD->getParent()->getDefinition();
994 if (!ClassDecl)
995 return;
996
997 const auto UseFields = [&](const CXXRecordDecl *RD) {
998 for (const auto *Field : RD->fields())
999 if (auto *FieldList = getOriginsList(*Field))
1000 CurrentBlockFacts.push_back(
1001 FactMgr.createFact<UseFact>(Call, FieldList));
1002 };
1003
1004 UseFields(ClassDecl);
1005
1006 ClassDecl->forallBases([&](const CXXRecordDecl *Base) {
1007 UseFields(Base);
1008 return true;
1009 });
1010}
1011
1012void FactsGenerator::handleLifetimeCaptureBy(const FunctionDecl *FD,
1013 ArrayRef<const Expr *> Args) {
1014 if (Args.empty())
1015 return;
1016 // FIXME: Add support for capture_by on constructors.
1018 return;
1019 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
1020 bool IsInstance =
1021 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD);
1022 auto getArgCaptureBy = [FD,
1023 IsInstance](unsigned I) -> LifetimeCaptureByAttr * {
1024 const ParmVarDecl *PVD = nullptr;
1025 if (IsInstance) {
1026 // FIXME: Add support for I == 0 i.e. capture_by on function declarations
1027 if (I > 0 && I - 1 < FD->getNumParams())
1028 PVD = FD->getParamDecl(I - 1);
1029 } else {
1030 if (I < FD->getNumParams())
1031 PVD = FD->getParamDecl(I);
1032 }
1033 return PVD ? PVD->getAttr<LifetimeCaptureByAttr>() : nullptr;
1034 };
1035 for (unsigned I = 0; I < Args.size(); ++I) {
1036 const LifetimeCaptureByAttr *Attr = getArgCaptureBy(I);
1037 if (!Attr)
1038 continue;
1039 OriginList *CapturedOriginList = getOriginsList(*Args[I]);
1040 if (!CapturedOriginList)
1041 continue;
1042 if (!CapturedOriginList)
1043 continue;
1044 for (int CapturingArgIdx : Attr->params()) {
1045 // FIXME: Add support for capturing to Global/unknown.
1046 if (CapturingArgIdx == LifetimeCaptureByAttr::Global ||
1047 CapturingArgIdx == LifetimeCaptureByAttr::Unknown ||
1048 CapturingArgIdx == LifetimeCaptureByAttr::Invalid)
1049 continue;
1050 ArrayRef<const Expr *> CallArgs = IsInstance ? Args.drop_front() : Args;
1051 const Expr *CapturedByArg =
1052 (CapturingArgIdx == LifetimeCaptureByAttr::This)
1053 ? Args[0]
1054 : CallArgs[CapturingArgIdx];
1055 assert(CapturedByArg && "Capturer expression must be valid");
1056
1057 OriginList *CapturingOriginList = getOriginsList(*CapturedByArg);
1058 OriginList *Dest = getRValueOrigins(CapturedByArg, CapturingOriginList);
1059 if (!Dest)
1060 continue;
1061 // KillDest=false because we cannot know if previous captures are being
1062 // replaced or accumulated. Multiple successive captures into the same
1063 // destination must all be tracked, so captured lifetimes are always
1064 // merged.
1065 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1066 Dest->getOuterOriginID(), CapturedOriginList->getOuterOriginID(),
1067 /*KillDest=*/false));
1068 }
1069 }
1070}
1071
1072void FactsGenerator::handleFunctionCall(const Expr *Call,
1073 const FunctionDecl *FD,
1074 ArrayRef<const Expr *> Args,
1075 bool IsGslConstruction) {
1076 OriginList *CallList = getOriginsList(*Call);
1077 // Ignore functions returning values with no origin.
1079 if (!FD)
1080 return;
1081 // All arguments to a function are a use of the corresponding expressions.
1082 for (const Expr *Arg : Args)
1083 handleUse(Arg);
1084 handleInvalidatingCall(Call, FD, Args);
1085 handleDestructiveCall(Call, FD, Args);
1086 handleMovedArgsInCall(FD, Args);
1087 handleImplicitObjectFieldUses(Call, FD);
1088 handleLifetimeCaptureBy(FD, Args);
1089 if (!CallList)
1090 return;
1091 if (isStdReferenceCast(FD)) {
1092 assert(Args.size() == 1 &&
1093 "std reference cast builtins take exactly one argument");
1094 // std reference-cast functions like std::move return a result that refers
1095 // to the same object as the argument, so propagate the full origins.
1096 flow(CallList, getOriginsList(*Args[0]), /*Kill=*/true);
1097 return;
1098 }
1099 auto IsArgLifetimeBound = [FD, &Args](unsigned I) -> bool {
1100 const ParmVarDecl *PVD = nullptr;
1101 if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
1102 Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD)) {
1103 if (I == 0)
1104 // For the 'this' argument, the attribute is on the method itself.
1107 *Args[0], Method, /*RunningUnderLifetimeSafety=*/true);
1108 if ((I - 1) < Method->getNumParams())
1109 // For explicit arguments, find the corresponding parameter
1110 // declaration.
1111 PVD = Method->getParamDecl(I - 1);
1112 } else if (I == 0 && shouldTrackFirstArgument(FD)) {
1113 return true;
1114 } else if (I == 1 && shouldTrackSecondArgument(FD)) {
1115 return true;
1116 } else if (I < FD->getNumParams()) {
1117 // For free functions or static methods.
1118 PVD = FD->getParamDecl(I);
1119 }
1120 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() : false;
1121 };
1122 auto shouldTrackPointerImplicitObjectArg = [FD, &Args](unsigned I) -> bool {
1123 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
1124 if (!Method || !Method->isInstance())
1125 return false;
1126 return I == 0 &&
1127 isGslPointerType(Method->getFunctionObjectParameterType()) &&
1129 /*RunningUnderLifetimeSafety=*/true);
1130 };
1131 if (Args.empty())
1132 return;
1133 bool KillSrc = true;
1134 for (unsigned I = 0; I < Args.size(); ++I) {
1135 OriginList *ArgList = getOriginsList(*Args[I]);
1136 if (!ArgList)
1137 continue;
1138 if (IsGslConstruction) {
1139 // TODO: document with code example.
1140 // std::string_view(const std::string_view& from)
1141 if (isGslPointerType(Args[I]->getType())) {
1142 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
1143 ArgList = getRValueOrigins(Args[I], ArgList);
1144 }
1145 if (isGslOwnerType(Args[I]->getType())) {
1146 // The constructed gsl::Pointer borrows from the Owner's storage, not
1147 // from what the Owner itself borrows, so only the outermost origin is
1148 // needed.
1149 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1150 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
1151 KillSrc));
1152 KillSrc = false;
1153 } else if (IsArgLifetimeBound(I)) {
1154 // Only flow the outer origin here. For lifetimebound args in
1155 // gsl::Pointer construction, we do not have enough information to
1156 // safely match inner origins, so the source and
1157 // destination origin lists may have different lengths.
1158 // FIXME: Handle origin-shape mismatches gracefully so we can also flow
1159 // inner origins.
1160 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1161 CallList->getOuterOriginID(), ArgList->getOuterOriginID(),
1162 KillSrc));
1163 KillSrc = false;
1164 }
1165 } else if (shouldTrackPointerImplicitObjectArg(I)) {
1166 assert(ArgList->getLength() >= 2 &&
1167 "Object arg of pointer type should have at least two origins");
1168 // See through the GSLPointer reference to see the pointer's value.
1169 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1170 CallList->getOuterOriginID(),
1171 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
1172 KillSrc = false;
1173 } else if (IsArgLifetimeBound(I)) {
1174 // Lifetimebound on a non-GSL-ctor function means the returned
1175 // pointer/reference itself must not outlive the arguments. This
1176 // only constrains the top-level origin.
1177 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
1178 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
1179 KillSrc = false;
1180 }
1181 }
1182}
1183
1184/// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
1185/// If so, creates a `TestPointFact` and returns true.
1186bool FactsGenerator::handleTestPoint(const CXXFunctionalCastExpr *FCE) {
1187 if (!FCE->getType()->isVoidType())
1188 return false;
1189
1190 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
1191 if (const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
1192 llvm::StringRef LiteralValue = SL->getString();
1193 const std::string Prefix = "__lifetime_test_point_";
1194
1195 if (LiteralValue.starts_with(Prefix)) {
1196 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
1197 CurrentBlockFacts.push_back(
1198 FactMgr.createFact<TestPointFact>(Annotation));
1199 return true;
1200 }
1201 }
1202 return false;
1203}
1204
1205void FactsGenerator::handleUse(const Expr *E) {
1206 OriginList *List = getOriginsList(*E);
1207 if (!List)
1208 return;
1209 // For DeclRefExpr: Remove the outer layer of origin which borrows from the
1210 // decl directly (e.g., when this is not a reference). This is a use of the
1211 // underlying decl.
1212 if (auto *DRE = dyn_cast<DeclRefExpr>(E);
1213 DRE && !DRE->getDecl()->getType()->isReferenceType())
1214 List = getRValueOrigins(DRE, List);
1215 // Skip if there is no inner origin (e.g., when it is not a pointer type).
1216 if (!List)
1217 return;
1218 if (!UseFacts.contains(E)) {
1219 UseFact *UF = FactMgr.createFact<UseFact>(E, List);
1220 CurrentBlockFacts.push_back(UF);
1221 UseFacts[E] = UF;
1222 }
1223}
1224
1225void FactsGenerator::markUseAsWrite(const DeclRefExpr *DRE) {
1226 if (UseFacts.contains(DRE))
1227 UseFacts[DRE]->markAsWritten();
1228}
1229
1230// Creates an IssueFact for a new placeholder loan for each pointer or reference
1231// parameter at the function's entry.
1232llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
1233 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
1234 if (!FD)
1235 return {};
1236
1237 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
1238 if (auto ThisOrigins = FactMgr.getOriginMgr().getThisOrigins()) {
1239 OriginList *List = *ThisOrigins;
1240 const Loan *L = FactMgr.getLoanMgr().createLoan(
1242 /*IssuingExpr=*/nullptr);
1243 PlaceholderLoanFacts.push_back(
1244 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
1245 }
1246 for (const ParmVarDecl *PVD : FD->parameters()) {
1247 OriginList *List = getOriginsList(*PVD);
1248 if (!List)
1249 continue;
1250 const Loan *L = FactMgr.getLoanMgr().createLoan(
1251 AccessPath::Placeholder(PVD), /*IssuingExpr=*/nullptr);
1252 PlaceholderLoanFacts.push_back(
1253 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
1254 }
1255 return PlaceholderLoanFacts;
1256}
1257
1258} // 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:4359
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4543
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4549
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition Expr.h:2727
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4044
Expr * getLHS() const
Definition Expr.h:4094
Expr * getRHS() const
Definition Expr.h:4096
static bool isAdditiveOp(Opcode Opc)
Definition Expr.h:4130
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4180
static bool isCompoundAssignmentOp(Opcode Opc)
Definition Expr.h:4185
Opcode getOpcode() const
Definition Expr.h:4089
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:3067
Represents a C++ base or member initializer.
Definition DeclCXX.h:2398
Expr * getInit() const
Get the initializer.
Definition DeclCXX.h:2600
FieldDecl * getAnyMember() const
Definition DeclCXX.h:2544
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:1112
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
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Definition ExprCXX.cpp:748
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition ExprCXX.cpp:729
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2145
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
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2949
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3132
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
Expr ** getArgs()
Retrieve the call arguments.
Definition Expr.h:3143
Decl * getCalleeDecl()
Definition Expr.h:3126
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3682
CastKind getCastKind() const
Definition Expr.h:3726
Expr * getSubExpr()
Definition Expr.h:3732
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1276
NamedDecl * getFoundDecl()
Get the NamedDecl through which this reference occurred.
Definition Expr.h:1387
ValueDecl * getDecl()
Definition Expr.h:1344
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1641
decl_range decls()
Definition Stmt.h:1689
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:112
bool isGLValue() const
Definition Expr.h:287
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3099
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3095
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3195
Represents a function declaration or definition.
Definition Decl.h:2027
bool isStatic() const
Definition Decl.h:2960
bool isDefaulted() const
Whether this function is defaulted.
Definition Decl.h:2412
Describes an C or C++ initializer list.
Definition Expr.h:5305
unsigned getNumInits() const
Definition Expr.h:5338
const Expr * getInit(unsigned Init) const
Definition Expr.h:5360
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:4920
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Definition ExprCXX.h:4945
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
Definition ExprCXX.h:4937
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3370
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3453
Expr * getBase() const
Definition Expr.h:3447
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition TypeBase.h:3392
A (possibly-)qualified type.
Definition TypeBase.h:937
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3170
Expr * getRetValue()
Definition Stmt.h:3197
StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}).
Definition Expr.h:4601
CompoundStmt * getSubStmt()
Definition Expr.h:4618
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:9050
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:8684
bool isReferenceType() const
Definition TypeBase.h:8708
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isPointerOrReferenceType() const
Definition TypeBase.h:8688
bool isFunctionType() const
Definition TypeBase.h:8680
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2250
Expr * getSubExpr() const
Definition Expr.h:2291
Opcode getOpcode() const
Definition Expr.h:2286
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:712
Represents a variable declaration or definition.
Definition Decl.h:932
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
Definition Loans.h:45
static AccessPath Placeholder(const ParmVarDecl *PVD)
Definition Loans.h:64
FactType * createFact(Args &&...args)
Definition Facts.h:365
An abstract base class for a single, atomic lifetime-relevant event.
Definition Facts.h:37
const T * getAs() const
Definition Facts.h:79
void VisitDeclRefExpr(const DeclRefExpr *DRE)
void VisitBinaryOperator(const BinaryOperator *BO)
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE)
void VisitCXXConstructExpr(const CXXConstructExpr *CCE)
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 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:270
Loan * createLoan(AccessPath Path, const Expr *IssueExpr)
Definition Loans.h:143
Represents lending a storage location.
Definition Loans.h:122
A list of origins representing levels of indirection for pointer-like types.
Definition Origins.h:95
OriginList * peelOuterOrigin() const
Definition Origins.h:99
OriginList * createSingleOriginList(OriginID OID)
Wraps an existing OriginID in a new single-element OriginList, so a fact can refer to a single level ...
Definition Origins.cpp:194
Represents that an origin escapes via a return statement.
Definition Facts.h:187
utils::ID< struct OriginTag > OriginID
Definition Origins.h:28
static OriginList * getRValueOrigins(const Expr *E, OriginList *List)
Simulates LValueToRValue conversion by peeling the outer lvalue origin if the expression is a GLValue...
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:161
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 shouldTrackFirstArgument(const FunctionDecl *FD)
bool shouldTrackImplicitObjectArg(const Expr &ImplicitObjectArgument, const CXXMethodDecl *Callee, bool RunningUnderLifetimeSafety)
bool isUniquePtrRelease(const CXXMethodDecl &MD)
bool isStdReferenceCast(const FunctionDecl *FD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isInvalidationMethod(const CXXMethodDecl &MD)
bool destructsFirstArg(const FunctionDecl &FD)
bool isGslOwnerType(QualType QT)
bool shouldTrackSecondArgument(const FunctionDecl *FD)
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ SD_FullExpression
Full-expression storage duration (for temporaries).
Definition Specifiers.h:341
U cast(CodeGen::Address addr)
Definition Address.h:327
#define false
Definition stdbool.h:26