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
17#include "llvm/Support/Casting.h"
18#include "llvm/Support/Signals.h"
19#include "llvm/Support/TimeProfiler.h"
20
22using llvm::isa_and_present;
23
24OriginList *FactsGenerator::getOriginsList(const ValueDecl &D) {
25 return FactMgr.getOriginMgr().getOrCreateList(&D);
26}
27OriginList *FactsGenerator::getOriginsList(const Expr &E) {
28 return FactMgr.getOriginMgr().getOrCreateList(&E);
29}
30
31/// Propagates origin information from Src to Dst through all levels of
32/// indirection, creating OriginFlowFacts at each level.
33///
34/// This function enforces a critical type-safety invariant: both lists must
35/// have the same shape (same depth/structure). This invariant ensures that
36/// origins flow only between compatible types during expression evaluation.
37///
38/// Examples:
39/// - `int* p = &x;` flows origins from `&x` (depth 1) to `p` (depth 1)
40/// - `int** pp = &p;` flows origins from `&p` (depth 2) to `pp` (depth 2)
41/// * Level 1: pp <- p's address
42/// * Level 2: (*pp) <- what p points to (i.e., &x)
43/// - `View v = obj;` flows origins from `obj` (depth 1) to `v` (depth 1)
44void FactsGenerator::flow(OriginList *Dst, OriginList *Src, bool Kill) {
45 if (!Dst)
46 return;
47 assert(Src &&
48 "Dst is non-null but Src is null. List must have the same length");
49 assert(Dst->getLength() == Src->getLength() &&
50 "Lists must have the same length");
51
52 while (Dst && Src) {
53 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
54 Dst->getOuterOriginID(), Src->getOuterOriginID(), Kill));
55 Dst = Dst->peelOuterOrigin();
56 Src = Src->peelOuterOrigin();
57 }
58}
59
60/// Creates a loan for the storage path of a given declaration reference.
61/// This function should be called whenever a DeclRefExpr represents a borrow.
62/// \param DRE The declaration reference expression that initiates the borrow.
63/// \return The new Loan on success, nullptr otherwise.
64static const PathLoan *createLoan(FactManager &FactMgr,
65 const DeclRefExpr *DRE) {
66 if (const auto *VD = dyn_cast<ValueDecl>(DRE->getDecl())) {
67 AccessPath Path(VD);
68 // The loan is created at the location of the DeclRefExpr.
69 return FactMgr.getLoanMgr().createLoan<PathLoan>(Path, DRE);
70 }
71 return nullptr;
72}
73
74/// Creates a loan for the storage location of a temporary object.
75/// \param MTE The MaterializeTemporaryExpr that represents the temporary
76/// binding. \return The new Loan.
77static const PathLoan *createLoan(FactManager &FactMgr,
78 const MaterializeTemporaryExpr *MTE) {
79 AccessPath Path(MTE);
80 return FactMgr.getLoanMgr().createLoan<PathLoan>(Path, MTE);
81}
82
83/// Try to find a CXXBindTemporaryExpr that descends from MTE, stripping away
84/// any implicit casts.
85/// \param MTE MaterializeTemporaryExpr whose descendants we are interested in.
86/// \return Pointer to descendant CXXBindTemporaryExpr or nullptr when not
87/// found.
88static const CXXBindTemporaryExpr *
90 const Expr *Child = MTE->getSubExpr()->IgnoreImpCasts();
91 return dyn_cast<CXXBindTemporaryExpr>(Child);
92}
93
95 llvm::TimeTraceScope TimeProfile("FactGenerator");
96 const CFG &Cfg = *AC.getCFG();
97 llvm::SmallVector<Fact *> PlaceholderLoanFacts = issuePlaceholderLoans();
98 // Iterate through the CFG blocks in reverse post-order to ensure that
99 // initializations and destructions are processed in the correct sequence.
100 for (const CFGBlock *Block : *AC.getAnalysis<PostOrderCFGView>()) {
101 CurrentBlockFacts.clear();
102 EscapesInCurrentBlock.clear();
103 if (Block == &Cfg.getEntry())
104 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
105 PlaceholderLoanFacts.end());
106 for (unsigned I = 0; I < Block->size(); ++I) {
107 const CFGElement &Element = Block->Elements[I];
108 if (std::optional<CFGStmt> CS = Element.getAs<CFGStmt>())
109 Visit(CS->getStmt());
110 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
111 Element.getAs<CFGLifetimeEnds>())
112 handleLifetimeEnds(*LifetimeEnds);
113 else if (std::optional<CFGTemporaryDtor> TemporaryDtor =
114 Element.getAs<CFGTemporaryDtor>())
115 handleTemporaryDtor(*TemporaryDtor);
116 }
117 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
118 EscapesInCurrentBlock.end());
119 FactMgr.addBlockFacts(Block, CurrentBlockFacts);
120 }
121}
122
123/// Simulates LValueToRValue conversion by peeling the outer lvalue origin
124/// if the expression is a GLValue. For pointer/view GLValues, this strips
125/// the origin representing the storage location to get the origins of the
126/// pointed-to value.
127///
128/// Example: For `View& v`, returns the origin of what v points to, not v's
129/// storage.
130static OriginList *getRValueOrigins(const Expr *E, OriginList *List) {
131 if (!List)
132 return nullptr;
133 return E->isGLValue() ? List->peelOuterOrigin() : List;
134}
135
137 for (const Decl *D : DS->decls())
138 if (const auto *VD = dyn_cast<VarDecl>(D))
139 if (const Expr *InitExpr = VD->getInit()) {
140 OriginList *VDList = getOriginsList(*VD);
141 if (!VDList)
142 continue;
143 OriginList *InitList = getOriginsList(*InitExpr);
144 assert(InitList && "VarDecl had origins but InitExpr did not");
145 flow(VDList, InitList, /*Kill=*/true);
146 }
147}
148
150 // Skip function references as their lifetimes are not interesting. Skip non
151 // GLValues (like EnumConstants).
152 if (DRE->getFoundDecl()->isFunctionOrFunctionTemplate() || !DRE->isGLValue())
153 return;
154 handleUse(DRE);
155 // For all declarations with storage (non-references), we issue a loan
156 // representing the borrow of the variable's storage itself.
157 //
158 // Examples:
159 // - `int x; x` issues loan to x's storage
160 // - `int* p; p` issues loan to p's storage (the pointer variable)
161 // - `View v; v` issues loan to v's storage (the view object)
162 // - `int& r = x; r` issues no loan (r has no storage, it's an alias to x)
163 if (doesDeclHaveStorage(DRE->getDecl())) {
164 const Loan *L = createLoan(FactMgr, DRE);
165 assert(L);
166 OriginList *List = getOriginsList(*DRE);
167 assert(List &&
168 "gl-value DRE of non-pointer type should have an origin list");
169 // This loan specifically tracks borrowing the variable's storage location
170 // itself and is issued to outermost origin (List->OID).
171 CurrentBlockFacts.push_back(
172 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
173 }
174}
175
177 if (isGslPointerType(CCE->getType())) {
178 handleGSLPointerConstruction(CCE);
179 return;
180 }
181}
182
184 // Specifically for conversion operators,
185 // like `std::string_view p = std::string{};`
186 if (isGslPointerType(MCE->getType()) &&
187 isa_and_present<CXXConversionDecl>(MCE->getCalleeDecl()) &&
189 // The argument is the implicit object itself.
190 handleFunctionCall(MCE, MCE->getMethodDecl(),
191 {MCE->getImplicitObjectArgument()},
192 /*IsGslConstruction=*/true);
193 return;
194 }
195 if (const CXXMethodDecl *Method = MCE->getMethodDecl()) {
196 // Construct the argument list, with the implicit 'this' object as the
197 // first argument.
199 Args.push_back(MCE->getImplicitObjectArgument());
200 Args.append(MCE->getArgs(), MCE->getArgs() + MCE->getNumArgs());
201
202 handleFunctionCall(MCE, Method, Args, /*IsGslConstruction=*/false);
203 }
204}
205
207 auto *MD = ME->getMemberDecl();
208 if (isa<FieldDecl>(MD) && doesDeclHaveStorage(MD)) {
209 assert(ME->isGLValue() && "Field member should be GL value");
210 OriginList *Dst = getOriginsList(*ME);
211 assert(Dst && "Field member should have an origin list as it is GL value");
212 OriginList *Src = getOriginsList(*ME->getBase());
213 assert(Src && "Base expression should be a pointer/reference type");
214 // The field's glvalue (outermost origin) holds the same loans as the base
215 // expression.
216 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
217 Dst->getOuterOriginID(), Src->getOuterOriginID(),
218 /*Kill=*/true));
219 }
220}
221
222static bool isStdMove(const FunctionDecl *FD) {
223 return FD && FD->isInStdNamespace() && FD->getIdentifier() &&
224 FD->getName() == "move";
225}
226
228 handleFunctionCall(CE, CE->getDirectCallee(),
229 {CE->getArgs(), CE->getNumArgs()});
230 // Track declarations that are moved via std::move.
231 // This is a flow-insensitive approximation: once a declaration is moved
232 // anywhere in the function, it's treated as moved everywhere. We do not
233 // generate expire facts for moved decls to avoid false alarms.
234 if (isStdMove(CE->getDirectCallee()))
235 if (CE->getNumArgs() == 1)
236 if (auto *DRE =
237 dyn_cast<DeclRefExpr>(CE->getArg(0)->IgnoreParenImpCasts()))
238 MovedDecls.insert(DRE->getDecl());
239}
240
242 const CXXNullPtrLiteralExpr *N) {
243 /// TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
244 /// pointers can use the same type of loan.
245 getOriginsList(*N);
246}
247
249 OriginList *Dest = getOriginsList(*ICE);
250 if (!Dest)
251 return;
252 const Expr *SubExpr = ICE->getSubExpr();
253 OriginList *Src = getOriginsList(*SubExpr);
254
255 switch (ICE->getCastKind()) {
256 case CK_LValueToRValue:
257 // TODO: Decide what to do for x-values here.
258 if (!SubExpr->isLValue())
259 return;
260
261 assert(Src && "LValue being cast to RValue has no origin list");
262 // The result of an LValue-to-RValue cast on a pointer lvalue (like `q` in
263 // `int *p, *q; p = q;`) should propagate the inner origin (what the pointer
264 // points to), not the outer origin (the pointer's storage location). Strip
265 // the outer lvalue origin.
266 flow(getOriginsList(*ICE), getRValueOrigins(SubExpr, Src),
267 /*Kill=*/true);
268 return;
269 case CK_NullToPointer:
270 getOriginsList(*ICE);
271 // TODO: Flow into them a null origin.
272 return;
273 case CK_NoOp:
274 case CK_ConstructorConversion:
275 case CK_UserDefinedConversion:
276 flow(Dest, Src, /*Kill=*/true);
277 return;
278 case CK_UncheckedDerivedToBase:
279 case CK_DerivedToBase:
280 // It is possible that the derived class and base class have different
281 // gsl::Pointer annotations. Skip if their origin shape differ.
282 if (Dest && Src && Dest->getLength() == Src->getLength())
283 flow(Dest, Src, /*Kill=*/true);
284 return;
285 case CK_FunctionToPointerDecay:
286 case CK_BuiltinFnToFnPtr:
287 case CK_ArrayToPointerDecay:
288 // Ignore function-to-pointer decays.
289 return;
290 default:
291 return;
292 }
293}
294
296 switch (UO->getOpcode()) {
297 case UO_AddrOf: {
298 const Expr *SubExpr = UO->getSubExpr();
299 // The origin of an address-of expression (e.g., &x) is the origin of
300 // its sub-expression (x). This fact will cause the dataflow analysis
301 // to propagate any loans held by the sub-expression's origin to the
302 // origin of this UnaryOperator expression.
303 killAndFlowOrigin(*UO, *SubExpr);
304 return;
305 }
306 case UO_Deref: {
307 const Expr *SubExpr = UO->getSubExpr();
308 killAndFlowOrigin(*UO, *SubExpr);
309 return;
310 }
311 default:
312 return;
313 }
314}
315
317 if (const Expr *RetExpr = RS->getRetValue()) {
318 if (OriginList *List = getOriginsList(*RetExpr))
319 for (OriginList *L = List; L != nullptr; L = L->peelOuterOrigin())
320 EscapesInCurrentBlock.push_back(FactMgr.createFact<OriginEscapesFact>(
321 L->getOuterOriginID(), RetExpr));
322 }
323}
324
325void FactsGenerator::handleAssignment(const Expr *LHSExpr,
326 const Expr *RHSExpr) {
327 if (const auto *DRE_LHS =
328 dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts())) {
329 OriginList *LHSList = getOriginsList(*DRE_LHS);
330 assert(LHSList && "LHS is a DRE and should have an origin list");
331 OriginList *RHSList = getOriginsList(*RHSExpr);
332
333 // For operator= with reference parameters (e.g.,
334 // `View& operator=(const View&)`), the RHS argument stays an lvalue,
335 // unlike built-in assignment where LValueToRValue cast strips the outer
336 // lvalue origin. Strip it manually to get the actual value origins being
337 // assigned.
338 RHSList = getRValueOrigins(RHSExpr, RHSList);
339
340 markUseAsWrite(DRE_LHS);
341 // Kill the old loans of the destination origin and flow the new loans
342 // from the source origin.
343 flow(LHSList->peelOuterOrigin(), RHSList, /*Kill=*/true);
344 }
345}
346
348 // TODO: Handle pointer arithmetic (e.g., `p + 1` or `1 + p`) where the
349 // result should have the same loans as the pointer operand.
350 if (BO->isCompoundAssignmentOp())
351 return;
352 if (BO->isAssignmentOp())
353 handleAssignment(BO->getLHS(), BO->getRHS());
354 // TODO: Handle assignments involving dereference like `*p = q`.
355}
356
358 if (hasOrigins(CO)) {
359 // Merge origins from both branches of the conditional operator.
360 // We kill to clear the initial state and merge both origins into it.
361 killAndFlowOrigin(*CO, *CO->getTrueExpr());
362 flowOrigin(*CO, *CO->getFalseExpr());
363 }
364}
365
367 // Assignment operators have special "kill-then-propagate" semantics
368 // and are handled separately.
369 if (OCE->getOperator() == OO_Equal && OCE->getNumArgs() == 2 &&
370 hasOrigins(OCE->getArg(0)->getType())) {
371 handleAssignment(OCE->getArg(0), OCE->getArg(1));
372 return;
373 }
374 VisitCallExpr(OCE);
375}
376
378 const CXXFunctionalCastExpr *FCE) {
379 // Check if this is a test point marker. If so, we are done with this
380 // expression.
381 if (handleTestPoint(FCE))
382 return;
383 if (isGslPointerType(FCE->getType()))
384 killAndFlowOrigin(*FCE, *FCE->getSubExpr());
385}
386
388 if (!hasOrigins(ILE))
389 return;
390 // For list initialization with a single element, like `View{...}`, the
391 // origin of the list itself is the origin of its single element.
392 if (ILE->getNumInits() == 1)
393 killAndFlowOrigin(*ILE, *ILE->getInit(0));
394}
395
397 const MaterializeTemporaryExpr *MTE) {
398 assert(MTE->isGLValue());
399 // We defer from handling lifetime extended materializations.
401 return;
402 OriginList *MTEList = getOriginsList(*MTE);
403 if (!MTEList)
404 return;
405 OriginList *SubExprList = getOriginsList(*MTE->getSubExpr());
406 assert((!SubExprList ||
407 MTEList->getLength() == (SubExprList->getLength() + 1)) &&
408 "MTE top level origin should contain a loan to the MTE itself");
409 MTEList = getRValueOrigins(MTE, MTEList);
410 if (getChildBinding(MTE)) {
411 // Issue a loan to MTE for the storage location represented by MTE.
412 const Loan *L = createLoan(FactMgr, MTE);
413 OriginList *List = getOriginsList(*MTE);
414 CurrentBlockFacts.push_back(
415 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
416 }
417 flow(MTEList, SubExprList, /*Kill=*/true);
418}
419
420void FactsGenerator::handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds) {
421 /// TODO: Handle loans to temporaries.
422 const VarDecl *LifetimeEndsVD = LifetimeEnds.getVarDecl();
423 if (!LifetimeEndsVD)
424 return;
425 // Iterate through all loans to see if any expire.
426 for (const auto *Loan : FactMgr.getLoanMgr().getLoans()) {
427 if (const auto *BL = dyn_cast<PathLoan>(Loan)) {
428 // Skip loans for declarations that have been moved. When a value is
429 // moved, the original owner no longer has ownership and its destruction
430 // should not cause the loan to expire, preventing false positives.
431 if (MovedDecls.contains(BL->getAccessPath().getAsValueDecl()))
432 continue;
433 // Check if the loan is for a stack variable and if that variable
434 // is the one being destructed.
435 const AccessPath AP = BL->getAccessPath();
436 const ValueDecl *Path = AP.getAsValueDecl();
437 if (Path == LifetimeEndsVD)
438 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
439 BL->getID(), LifetimeEnds.getTriggerStmt()->getEndLoc()));
440 }
441 }
442}
443
444void FactsGenerator::handleTemporaryDtor(
445 const CFGTemporaryDtor &TemporaryDtor) {
446 const CXXBindTemporaryExpr *ExpiringBTE =
447 TemporaryDtor.getBindTemporaryExpr();
448 if (!ExpiringBTE)
449 return;
450 // Iterate through all loans to see if any expire.
451 for (const auto *Loan : FactMgr.getLoanMgr().getLoans()) {
452 if (const auto *PL = dyn_cast<PathLoan>(Loan)) {
453 // Check if the loan is for a temporary materialization and if that
454 // storage location is the one being destructed.
455 const AccessPath &AP = PL->getAccessPath();
456 const MaterializeTemporaryExpr *Path = AP.getAsMaterializeTemporaryExpr();
457 if (!Path)
458 continue;
459 if (ExpiringBTE == getChildBinding(Path)) {
460 CurrentBlockFacts.push_back(FactMgr.createFact<ExpireFact>(
461 PL->getID(), TemporaryDtor.getBindTemporaryExpr()->getEndLoc()));
462 }
463 }
464 }
465}
466
467void FactsGenerator::handleGSLPointerConstruction(const CXXConstructExpr *CCE) {
468 assert(isGslPointerType(CCE->getType()));
469 if (CCE->getNumArgs() != 1)
470 return;
471
472 const Expr *Arg = CCE->getArg(0);
473 if (isGslPointerType(Arg->getType())) {
474 OriginList *ArgList = getOriginsList(*Arg);
475 assert(ArgList && "GSL pointer argument should have an origin list");
476 // GSL pointer is constructed from another gsl pointer.
477 // Example:
478 // View(View v);
479 // View(const View &v);
480 ArgList = getRValueOrigins(Arg, ArgList);
481 flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
482 } else if (Arg->getType()->isPointerType()) {
483 // GSL pointer is constructed from a raw pointer. Flow only the outermost
484 // raw pointer. Example:
485 // View(const char*);
486 // Span<int*>(const in**);
487 OriginList *ArgList = getOriginsList(*Arg);
488 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
489 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
490 /*Kill=*/true));
491 } else {
492 // This could be a new borrow.
493 // TODO: Add code example here.
494 handleFunctionCall(CCE, CCE->getConstructor(),
495 {CCE->getArgs(), CCE->getNumArgs()},
496 /*IsGslConstruction=*/true);
497 }
498}
499
500/// Checks if a call-like expression creates a borrow by passing a value to a
501/// reference parameter, creating an IssueFact if it does.
502/// \param IsGslConstruction True if this is a GSL construction where all
503/// argument origins should flow to the returned origin.
504void FactsGenerator::handleFunctionCall(const Expr *Call,
505 const FunctionDecl *FD,
506 ArrayRef<const Expr *> Args,
507 bool IsGslConstruction) {
508 OriginList *CallList = getOriginsList(*Call);
509 // Ignore functions returning values with no origin.
511 if (!FD || !CallList)
512 return;
513 auto IsArgLifetimeBound = [FD](unsigned I) -> bool {
514 const ParmVarDecl *PVD = nullptr;
515 if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
516 Method && Method->isInstance()) {
517 if (I == 0)
518 // For the 'this' argument, the attribute is on the method itself.
521 Method, /*RunningUnderLifetimeSafety=*/true);
522 if ((I - 1) < Method->getNumParams())
523 // For explicit arguments, find the corresponding parameter
524 // declaration.
525 PVD = Method->getParamDecl(I - 1);
526 } else if (I == 0 && shouldTrackFirstArgument(FD)) {
527 return true;
528 } else if (I < FD->getNumParams()) {
529 // For free functions or static methods.
530 PVD = FD->getParamDecl(I);
531 }
532 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() : false;
533 };
534 auto shouldTrackPointerImplicitObjectArg = [FD](unsigned I) -> bool {
535 const auto *Method = dyn_cast<CXXMethodDecl>(FD);
536 if (!Method || !Method->isInstance())
537 return false;
538 return I == 0 &&
539 isGslPointerType(Method->getFunctionObjectParameterType()) &&
541 /*RunningUnderLifetimeSafety=*/true);
542 };
543 if (Args.empty())
544 return;
545 bool KillSrc = true;
546 for (unsigned I = 0; I < Args.size(); ++I) {
547 OriginList *ArgList = getOriginsList(*Args[I]);
548 if (!ArgList)
549 continue;
550 if (IsGslConstruction) {
551 // TODO: document with code example.
552 // std::string_view(const std::string_view& from)
553 if (isGslPointerType(Args[I]->getType())) {
554 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
555 ArgList = getRValueOrigins(Args[I], ArgList);
556 }
557 if (isGslOwnerType(Args[I]->getType())) {
558 // GSL construction creates a view that borrows from arguments.
559 // This implies flowing origins through the list structure.
560 flow(CallList, ArgList, KillSrc);
561 KillSrc = false;
562 }
563 } else if (shouldTrackPointerImplicitObjectArg(I)) {
564 assert(ArgList->getLength() >= 2 &&
565 "Object arg of pointer type should have atleast two origins");
566 // See through the GSLPointer reference to see the pointer's value.
567 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
568 CallList->getOuterOriginID(),
569 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
570 KillSrc = false;
571 } else if (IsArgLifetimeBound(I)) {
572 // Lifetimebound on a non-GSL-ctor function means the returned
573 // pointer/reference itself must not outlive the arguments. This
574 // only constraints the top-level origin.
575 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
576 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
577 KillSrc = false;
578 }
579 }
580}
581
582/// Checks if the expression is a `void("__lifetime_test_point_...")` cast.
583/// If so, creates a `TestPointFact` and returns true.
584bool FactsGenerator::handleTestPoint(const CXXFunctionalCastExpr *FCE) {
585 if (!FCE->getType()->isVoidType())
586 return false;
587
588 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
589 if (const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
590 llvm::StringRef LiteralValue = SL->getString();
591 const std::string Prefix = "__lifetime_test_point_";
592
593 if (LiteralValue.starts_with(Prefix)) {
594 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
595 CurrentBlockFacts.push_back(
596 FactMgr.createFact<TestPointFact>(Annotation));
597 return true;
598 }
599 }
600 return false;
601}
602
603// A DeclRefExpr will be treated as a use of the referenced decl. It will be
604// checked for use-after-free unless it is later marked as being written to
605// (e.g. on the left-hand side of an assignment).
606void FactsGenerator::handleUse(const DeclRefExpr *DRE) {
607 OriginList *List = getOriginsList(*DRE);
608 if (!List)
609 return;
610 // Remove the outer layer of origin which borrows from the decl directly
611 // (e.g., when this is not a reference). This is a use of the underlying decl.
612 if (!DRE->getDecl()->getType()->isReferenceType())
613 List = getRValueOrigins(DRE, List);
614 // Skip if there is no inner origin (e.g., when it is not a pointer type).
615 if (!List)
616 return;
617 UseFact *UF = FactMgr.createFact<UseFact>(DRE, List);
618 CurrentBlockFacts.push_back(UF);
619 assert(!UseFacts.contains(DRE));
620 UseFacts[DRE] = UF;
621}
622
623void FactsGenerator::markUseAsWrite(const DeclRefExpr *DRE) {
624 if (UseFacts.contains(DRE))
625 UseFacts[DRE]->markAsWritten();
626}
627
628// Creates an IssueFact for a new placeholder loan for each pointer or reference
629// parameter at the function's entry.
630llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
631 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
632 if (!FD)
633 return {};
634
635 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
636 if (const auto *MD = dyn_cast<CXXMethodDecl>(FD); MD && MD->isInstance()) {
637 OriginList *List = *FactMgr.getOriginMgr().getThisOrigins();
638 const PlaceholderLoan *L =
639 FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(MD);
640 PlaceholderLoanFacts.push_back(
641 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
642 }
643 for (const ParmVarDecl *PVD : FD->parameters()) {
644 OriginList *List = getOriginsList(*PVD);
645 if (!List)
646 continue;
647 const PlaceholderLoan *L =
648 FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(PVD);
649 PlaceholderLoanFacts.push_back(
650 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
651 }
652 return PlaceholderLoanFacts;
653}
654
655} // namespace clang::lifetimes::internal
TokenType getType() const
Returns the token's type, e.g.
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4038
Expr * getLHS() const
Definition Expr.h:4088
Expr * getRHS() const
Definition Expr.h:4090
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4174
static bool isCompoundAssignmentOp(Opcode Opc)
Definition Expr.h:4179
Represents a single basic block in a source-level CFG.
Definition CFG.h:605
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:109
Represents the point where the lifetime of an automatic object ends.
Definition CFG.h:293
const Stmt * getTriggerStmt() const
Definition CFG.h:302
const VarDecl * getVarDecl() const
Definition CFG.h:298
Represents C++ object destructor implicitly generated at the end of full expression for temporary obj...
Definition CFG.h:511
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1218
CFGBlock & getEntry()
Definition CFG.h:1327
Represents binding an expression to a temporary.
Definition ExprCXX.h:1493
Represents a call to a C++ constructor.
Definition ExprCXX.h:1548
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
Definition ExprCXX.h:1831
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:179
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Definition ExprCXX.cpp:741
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition ExprCXX.cpp:722
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2129
The null pointer literal (C++11 [lex.nullptr])
Definition ExprCXX.h:768
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:84
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Definition ExprCXX.h:114
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2943
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3147
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3126
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3134
Expr ** getArgs()
Retrieve the call arguments.
Definition Expr.h:3137
Decl * getCalleeDecl()
Definition Expr.h:3120
CastKind getCastKind() const
Definition Expr.h:3720
Expr * getSubExpr()
Definition Expr.h:3726
ConditionalOperator - The ?
Definition Expr.h:4391
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4423
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4418
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1270
NamedDecl * getFoundDecl()
Get the NamedDecl through which this reference occurred.
Definition Expr.h:1381
ValueDecl * getDecl()
Definition Expr.h:1338
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1623
decl_range decls()
Definition Stmt.h:1671
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isInStdNamespace() const
Definition DeclBase.cpp:449
bool isFunctionOrFunctionTemplate() const
Whether this declaration is a function or function template.
Definition DeclBase.h:1119
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:3089
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition Expr.h:284
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3069
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2000
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition Expr.h:3853
Describes an C or C++ initializer list.
Definition Expr.h:5299
unsigned getNumInits() const
Definition Expr.h:5329
const Expr * getInit(unsigned Init) const
Definition Expr.h:5353
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:3364
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3447
Expr * getBase() const
Definition Expr.h:3441
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:295
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3152
Expr * getRetValue()
Definition Stmt.h:3179
RetTy Visit(PTR(Stmt) S, ParamTys... P)
Definition StmtVisitor.h:45
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:362
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2244
Expr * getSubExpr() const
Definition Expr.h:2285
Opcode getOpcode() const
Definition Expr.h:2280
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:926
FactType * createFact(Args &&...args)
Definition Facts.h:212
void VisitDeclRefExpr(const DeclRefExpr *DRE)
void VisitBinaryOperator(const BinaryOperator *BO)
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE)
void VisitCXXConstructExpr(const CXXConstructExpr *CCE)
void VisitImplicitCastExpr(const ImplicitCastExpr *ICE)
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE)
void VisitInitListExpr(const InitListExpr *ILE)
void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N)
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)
void VisitUnaryOperator(const UnaryOperator *UO)
void VisitConditionalOperator(const ConditionalOperator *CO)
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE)
llvm::ArrayRef< const Loan * > getLoans() const
Definition Loans.h:167
LoanType * createLoan(Args &&...args)
Definition Loans.h:151
An abstract base class for a single "Loan" which represents lending a storage in memory.
Definition Loans.h:59
A list of origins representing levels of indirection for pointer-like types.
Definition Origins.h:94
OriginList * peelOuterOrigin() const
Definition Origins.h:98
PathLoan represents lending a storage location that is visible within the function's scope (e....
Definition Loans.h:87
static const CXXBindTemporaryExpr * getChildBinding(const MaterializeTemporaryExpr *MTE)
Try to find a CXXBindTemporaryExpr that descends from MTE, stripping away any implicit casts.
static const PathLoan * createLoan(FactManager &FactMgr, const DeclRefExpr *DRE)
Creates a loan for the storage path of a given declaration reference.
static OriginList * getRValueOrigins(const Expr *E, OriginList *List)
Simulates LValueToRValue conversion by peeling the outer lvalue origin if the expression is a GLValue...
static bool isStdMove(const FunctionDecl *FD)
bool doesDeclHaveStorage(const ValueDecl *D)
Returns true if the declaration has its own storage that can be borrowed.
Definition Origins.cpp:85
bool hasOrigins(QualType QT)
Definition Origins.cpp:52
bool isGslPointerType(QualType QT)
bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee, bool RunningUnderLifetimeSafety)
bool shouldTrackFirstArgument(const FunctionDecl *FD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isGslOwnerType(QualType QT)
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ SD_FullExpression
Full-expression storage duration (for temporaries).
Definition Specifiers.h:340
#define false
Definition stdbool.h:26
Represents the storage location being borrowed, e.g., a specific stack variable.
Definition Loans.h:33
const clang::ValueDecl * getAsValueDecl() const
Definition Loans.h:48