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"
31using llvm::isa_and_present;
33OriginList *FactsGenerator::getOriginsList(
const ValueDecl &D) {
34 return FactMgr.getOriginMgr().getOrCreateList(&D);
36OriginList *FactsGenerator::getOriginsList(
const Expr &E) {
37 return FactMgr.getOriginMgr().getOrCreateList(&E);
57 "Dst is non-null but Src is null. List must have the same length");
58 assert(Dst->getLength() == Src->getLength() &&
59 "Lists must have the same length");
62 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
63 Dst->getOuterOriginID(), Src->getOuterOriginID(), Kill));
64 Dst = Dst->peelOuterOrigin();
65 Src = Src->peelOuterOrigin();
90 llvm::TimeTraceScope TimeProfile(
"FactGenerator");
91 const CFG &Cfg = *AC.getCFG();
96 CurrentBlockFacts.clear();
97 EscapesInCurrentBlock.clear();
99 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
100 PlaceholderLoanFacts.end());
101 for (
unsigned I = 0; I <
Block->size(); ++I) {
103 if (std::optional<CFGStmt> CS = Element.
getAs<
CFGStmt>())
104 Visit(CS->getStmt());
105 else if (std::optional<CFGInitializer>
Initializer =
107 handleCXXCtorInitializer(
Initializer->getInitializer());
108 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
110 handleLifetimeEnds(*LifetimeEnds);
111 else if (std::optional<CFGFullExprCleanup> FullExprCleanup =
113 handleFullExprCleanup(*FullExprCleanup);
119 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
120 EscapesInCurrentBlock.end());
121 FactMgr.addBlockFacts(
Block, CurrentBlockFacts);
140 if (
const auto *VD = dyn_cast<VarDecl>(D))
141 if (
const Expr *InitExpr = VD->getInit()) {
145 OriginList *InitList = getOriginsList(*InitExpr);
146 assert(InitList &&
"VarDecl had origins but InitExpr did not");
147 flow(VDList, InitList,
true);
170 "gl-value DRE of non-pointer type should have an origin list");
173 CurrentBlockFacts.push_back(
180 handleGSLPointerConstruction(CCE);
193 flow(getOriginsList(*CCE), ArgList,
true);
198 {CCE->getArgs(), CCE->getNumArgs()},
206 killAndFlowOrigin(*FD, *CII->
getInit());
217 {MCE->getImplicitObjectArgument()},
228 handleFunctionCall(MCE,
Method, Args,
false);
235 assert(ME->
isGLValue() &&
"Field member should be GL value");
237 assert(Dst &&
"Field member should have an origin list as it is GL value");
239 assert(Src &&
"Base expression should be a pointer/reference type");
250 {CE->getArgs(), CE->getNumArgs()});
268 case CK_LValueToRValue:
273 assert(Src &&
"LValue being cast to RValue has no origin list");
281 case CK_NullToPointer:
282 getOriginsList(*ICE);
286 case CK_ConstructorConversion:
287 case CK_UserDefinedConversion:
288 flow(Dest, Src,
true);
290 case CK_UncheckedDerivedToBase:
291 case CK_DerivedToBase:
295 flow(Dest, Src,
true);
297 case CK_ArrayToPointerDecay:
298 assert(Src &&
"Array expression should have origins as it is GL value");
302 case CK_FunctionToPointerDecay:
303 case CK_BuiltinFnToFnPtr:
319 killAndFlowOrigin(*UO, *SubExpr);
324 killAndFlowOrigin(*UO, *SubExpr);
334 if (
OriginList *List = getOriginsList(*RetExpr))
337 L->getOuterOriginID(), RetExpr));
341void FactsGenerator::handleAssignment(
const Expr *LHSExpr,
342 const Expr *RHSExpr) {
346 if (
const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
347 LHSList = getOriginsList(*DRE_LHS);
348 assert(LHSList &&
"LHS is a DRE and should have an origin list");
353 if (
const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
354 LHSList = getOriginsList(*ME_LHS);
355 assert(LHSList &&
"LHS is a MemberExpr and should have an origin list");
359 OriginList *RHSList = getOriginsList(*RHSExpr);
367 if (
const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
368 markUseAsWrite(DRE_LHS);
407 Args = Args.slice(1);
415 if (handleTestPoint(FCE))
427 killAndFlowOrigin(*ILE, *ILE->
getInit(0));
442 assert((!SubExprList ||
444 "MTE top level origin should contain a loan to the MTE itself");
447 flow(RValMTEList, SubExprList,
true);
452 CurrentBlockFacts.push_back(
465 for (
const Expr *
Init : LE->capture_inits()) {
482 assert(ASE->
isGLValue() &&
"Array subscript should be a GL value");
484 assert(Dst &&
"Array subscript should have origins as it is a GL value");
486 assert(Src &&
"Base of array subscript should have origins");
491bool FactsGenerator::escapesViaReturn(
OriginID OID)
const {
492 return llvm::any_of(EscapesInCurrentBlock, [OID](
const Fact *F) {
494 return EF->getEscapedOriginID() == OID;
499void FactsGenerator::handleLifetimeEnds(
const CFGLifetimeEnds &LifetimeEnds) {
505 std::optional<OriginID> ExpiredOID;
506 if (OriginList *List = getOriginsList(*LifetimeEndsVD)) {
507 OriginID OID = List->getOuterOriginID();
510 if (!escapesViaReturn(OID))
513 CurrentBlockFacts.push_back(FactMgr.
createFact<ExpireFact>(
518void FactsGenerator::handleFullExprCleanup(
519 const CFGFullExprCleanup &FullExprCleanup) {
520 for (
const auto *MTE : FullExprCleanup.getExpiringMTEs())
521 CurrentBlockFacts.push_back(
522 FactMgr.createFact<ExpireFact>(AccessPath(MTE), MTE->getEndLoc()));
525void FactsGenerator::handleExitBlock() {
526 for (
const Origin &O : FactMgr.getOriginMgr().getOrigins())
527 if (
auto *FD = dyn_cast_if_present<FieldDecl>(O.getDecl()))
529 EscapesInCurrentBlock.push_back(
530 FactMgr.createFact<FieldEscapeFact>(O.ID, FD));
531 else if (
auto *VD = dyn_cast_if_present<VarDecl>(O.getDecl())) {
534 if (VD->hasGlobalStorage()) {
535 EscapesInCurrentBlock.push_back(
536 FactMgr.createFact<GlobalEscapeFact>(O.ID, VD));
541void FactsGenerator::handleGSLPointerConstruction(
const CXXConstructExpr *CCE) {
543 if (CCE->getNumArgs() != 1)
546 const Expr *Arg = CCE->getArg(0);
548 OriginList *ArgList = getOriginsList(*Arg);
549 assert(ArgList &&
"GSL pointer argument should have an origin list");
555 flow(getOriginsList(*CCE), ArgList,
true);
556 }
else if (Arg->getType()->isPointerType()) {
561 OriginList *ArgList = getOriginsList(*Arg);
562 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
563 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
568 handleFunctionCall(CCE, CCE->getConstructor(),
569 {CCE->getArgs(), CCE->getNumArgs()},
574void FactsGenerator::handleMovedArgsInCall(
const FunctionDecl *FD,
575 ArrayRef<const Expr *> Args) {
576 unsigned IsInstance = 0;
577 if (
const auto *MD = dyn_cast<CXXMethodDecl>(FD);
584 const Expr *UniquePtrExpr = Args[0];
585 OriginList *MovedOrigins = getOriginsList(*UniquePtrExpr);
587 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
588 UniquePtrExpr, MovedOrigins->getOuterOriginID()));
593 for (
unsigned I = IsInstance;
594 I < Args.size() && I < FD->getNumParams() + IsInstance; ++I) {
595 const ParmVarDecl *PVD = FD->getParamDecl(I - IsInstance);
596 if (!PVD->getType()->isRValueReferenceType())
598 const Expr *Arg = Args[I];
599 OriginList *MovedOrigins = getOriginsList(*Arg);
600 assert(MovedOrigins->getLength() >= 1 &&
601 "unexpected length for r-value reference param");
603 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
604 Arg, MovedOrigins->getOuterOriginID()));
608void FactsGenerator::handleInvalidatingCall(
const Expr *
Call,
609 const FunctionDecl *FD,
610 ArrayRef<const Expr *> Args) {
611 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
612 if (!MD || !MD->isInstance())
618 auto *DRE = dyn_cast<DeclRefExpr>(Args[0]);
619 if (!DRE || DRE->getDecl()->getType()->isReferenceType())
622 OriginList *ThisList = getOriginsList(*Args[0]);
624 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
625 ThisList->getOuterOriginID(),
Call));
628void FactsGenerator::handleFunctionCall(
const Expr *
Call,
629 const FunctionDecl *FD,
630 ArrayRef<const Expr *> Args,
631 bool IsGslConstruction) {
632 OriginList *CallList = getOriginsList(*
Call);
638 for (
const Expr *Arg : Args)
640 handleInvalidatingCall(
Call, FD, Args);
641 handleMovedArgsInCall(FD, Args);
644 auto IsArgLifetimeBound = [FD](
unsigned I) ->
bool {
645 const ParmVarDecl *PVD =
nullptr;
646 if (
const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
653 if ((I - 1) <
Method->getNumParams())
656 PVD =
Method->getParamDecl(I - 1);
659 }
else if (I < FD->getNumParams()) {
661 PVD = FD->getParamDecl(I);
663 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() :
false;
665 auto shouldTrackPointerImplicitObjectArg = [FD](
unsigned I) ->
bool {
666 const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
677 for (
unsigned I = 0; I < Args.size(); ++I) {
678 OriginList *ArgList = getOriginsList(*Args[I]);
681 if (IsGslConstruction) {
685 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
691 flow(CallList, ArgList, KillSrc);
694 }
else if (shouldTrackPointerImplicitObjectArg(I)) {
695 assert(ArgList->getLength() >= 2 &&
696 "Object arg of pointer type should have atleast two origins");
698 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
699 CallList->getOuterOriginID(),
700 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
702 }
else if (IsArgLifetimeBound(I)) {
706 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
707 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
715bool FactsGenerator::handleTestPoint(
const CXXFunctionalCastExpr *FCE) {
716 if (!FCE->getType()->isVoidType())
719 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
720 if (
const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
721 llvm::StringRef LiteralValue = SL->getString();
722 const std::string Prefix =
"__lifetime_test_point_";
724 if (LiteralValue.starts_with(Prefix)) {
725 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
726 CurrentBlockFacts.push_back(
727 FactMgr.createFact<TestPointFact>(Annotation));
734void FactsGenerator::handleUse(
const Expr *E) {
735 OriginList *List = getOriginsList(*E);
741 if (
auto *DRE = dyn_cast<DeclRefExpr>(E);
742 DRE && !DRE->getDecl()->
getType()->isReferenceType())
747 if (!UseFacts.contains(E)) {
748 UseFact *UF = FactMgr.createFact<UseFact>(E, List);
749 CurrentBlockFacts.push_back(UF);
754void FactsGenerator::markUseAsWrite(
const DeclRefExpr *DRE) {
755 if (UseFacts.contains(DRE))
756 UseFacts[DRE]->markAsWritten();
761llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
762 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
766 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
767 if (
auto ThisOrigins = FactMgr.getOriginMgr().getThisOrigins()) {
768 OriginList *List = *ThisOrigins;
769 const Loan *L = FactMgr.getLoanMgr().createLoan(
772 PlaceholderLoanFacts.push_back(
773 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
775 for (
const ParmVarDecl *PVD : FD->parameters()) {
776 OriginList *List = getOriginsList(*PVD);
779 const Loan *L = FactMgr.getLoanMgr().createLoan(
781 PlaceholderLoanFacts.push_back(
782 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
784 return PlaceholderLoanFacts;
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines an enumeration for C++ overloaded operators.
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isAssignmentOp(Opcode Opc)
static bool isCompoundAssignmentOp(Opcode Opc)
Represents a single basic block in a source-level CFG.
Represents a top-level expression in a basic block.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
Represents C++ base or member initializer from constructor's initialization list.
Represents the point where the lifetime of an automatic object ends.
const Stmt * getTriggerStmt() const
const VarDecl * getVarDecl() const
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Represents binding an expression to a temporary.
const Expr * getSubExpr() const
Represents a call to a C++ constructor.
Expr * getArg(unsigned Arg)
Return the specified argument.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
bool isCopyOrMoveConstructor(unsigned &TypeQuals) const
Determine whether this is a copy or move constructor.
Represents a C++ base or member initializer.
Expr * getInit() const
Get the initializer.
FieldDecl * getAnyMember() const
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
Represents a call to a member function that may be written either with member call syntax (e....
CXXMethodDecl * getMethodDecl() const
Retrieve the declaration of the called method.
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Represents a static or instance method of a struct/union/class.
The null pointer literal (C++11 [lex.nullptr])
A call to an overloaded operator written using operator syntax.
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
bool isLambda() const
Determine whether this class describes a lambda function object.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Expr ** getArgs()
Retrieve the call arguments.
CastKind getCastKind() const
ConditionalOperator - The ?
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
A reference to a declared variable, function, enum, etc.
NamedDecl * getFoundDecl()
Get the NamedDecl through which this reference occurred.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Decl - This represents one declaration (or definition), e.g.
bool isFunctionOrFunctionTemplate() const
Whether this declaration is a function or function template.
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Represents a member of a struct/union/class.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Describes an C or C++ initializer list.
unsigned getNumInits() const
const Expr * getInit(unsigned Init) const
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
StorageDuration getStorageDuration() const
Retrieve the storage duration for the materialized temporary.
Expr * getSubExpr() const
Retrieve the temporary-generating subexpression whose value will be materialized into a glvalue.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
RetTy Visit(PTR(Stmt) S, ParamTys... P)
SourceLocation getEndLoc() const LLVM_READONLY
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
Represents the storage location being borrowed, e.g., a specific stack variable or a field within it:...
static AccessPath Placeholder(const ParmVarDecl *PVD)
FactType * createFact(Args &&...args)
LoanManager & getLoanMgr()
An abstract base class for a single, atomic lifetime-relevant event.
void VisitDeclRefExpr(const DeclRefExpr *DRE)
void VisitBinaryOperator(const BinaryOperator *BO)
void VisitCallExpr(const CallExpr *CE)
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE)
void VisitReturnStmt(const ReturnStmt *RS)
void VisitCXXConstructExpr(const CXXConstructExpr *CCE)
void VisitImplicitCastExpr(const ImplicitCastExpr *ICE)
void VisitMemberExpr(const MemberExpr *ME)
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE)
void VisitInitListExpr(const InitListExpr *ILE)
void VisitLambdaExpr(const LambdaExpr *LE)
void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N)
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)
void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE)
void VisitUnaryOperator(const UnaryOperator *UO)
void VisitDeclStmt(const DeclStmt *DS)
void VisitConditionalOperator(const ConditionalOperator *CO)
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE)
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE)
Loan * createLoan(AccessPath Path, const Expr *IssueExpr)
Represents lending a storage location.
A list of origins representing levels of indirection for pointer-like types.
OriginID getOuterOriginID() const
OriginList * peelOuterOrigin() const
Represents that an origin escapes via a return statement.
utils::ID< struct OriginTag > OriginID
static OriginList * getRValueOrigins(const Expr *E, OriginList *List)
Simulates LValueToRValue conversion by peeling the outer lvalue origin if the expression is a GLValue...
bool doesDeclHaveStorage(const ValueDecl *D)
Returns true if the declaration has its own storage that can be borrowed.
static const Loan * createLoan(FactManager &FactMgr, const DeclRefExpr *DRE)
Creates a loan for the storage path of a given declaration reference.
bool hasOrigins(QualType QT)
bool isGslPointerType(QualType QT)
bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee, bool RunningUnderLifetimeSafety)
bool shouldTrackFirstArgument(const FunctionDecl *FD)
bool isContainerInvalidationMethod(const CXXMethodDecl &MD)
bool isUniquePtrRelease(const CXXMethodDecl &MD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
bool isGslOwnerType(QualType QT)
bool isa(CodeGen::Address addr)
@ SD_FullExpression
Full-expression storage duration (for temporaries).
U cast(CodeGen::Address addr)