18#include "llvm/Support/Casting.h"
19#include "llvm/Support/Signals.h"
20#include "llvm/Support/TimeProfiler.h"
23using llvm::isa_and_present;
25OriginList *FactsGenerator::getOriginsList(
const ValueDecl &D) {
26 return FactMgr.getOriginMgr().getOrCreateList(&D);
28OriginList *FactsGenerator::getOriginsList(
const Expr &E) {
29 return FactMgr.getOriginMgr().getOrCreateList(&E);
49 "Dst is non-null but Src is null. List must have the same length");
50 assert(Dst->getLength() == Src->getLength() &&
51 "Lists must have the same length");
54 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
55 Dst->getOuterOriginID(), Src->getOuterOriginID(), Kill));
56 Dst = Dst->peelOuterOrigin();
57 Src = Src->peelOuterOrigin();
67 if (
const auto *VD = dyn_cast<ValueDecl>(DRE->
getDecl())) {
92 return dyn_cast<CXXBindTemporaryExpr>(Child);
96 llvm::TimeTraceScope TimeProfile(
"FactGenerator");
97 const CFG &Cfg = *AC.getCFG();
102 CurrentBlockFacts.clear();
103 EscapesInCurrentBlock.clear();
105 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
106 PlaceholderLoanFacts.end());
107 for (
unsigned I = 0; I <
Block->size(); ++I) {
109 if (std::optional<CFGStmt> CS = Element.
getAs<
CFGStmt>())
110 Visit(CS->getStmt());
111 else if (std::optional<CFGInitializer>
Initializer =
113 handleCXXCtorInitializer(
Initializer->getInitializer());
114 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
116 handleLifetimeEnds(*LifetimeEnds);
117 else if (std::optional<CFGTemporaryDtor> TemporaryDtor =
119 handleTemporaryDtor(*TemporaryDtor);
124 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
125 EscapesInCurrentBlock.end());
126 FactMgr.addBlockFacts(
Block, CurrentBlockFacts);
145 if (
const auto *VD = dyn_cast<VarDecl>(D))
146 if (
const Expr *InitExpr = VD->getInit()) {
150 OriginList *InitList = getOriginsList(*InitExpr);
151 assert(InitList &&
"VarDecl had origins but InitExpr did not");
152 flow(VDList, InitList,
true);
175 "gl-value DRE of non-pointer type should have an origin list");
178 CurrentBlockFacts.push_back(
185 handleGSLPointerConstruction(CCE);
194 killAndFlowOrigin(*FD, *CII->
getInit());
205 {MCE->getImplicitObjectArgument()},
216 handleFunctionCall(MCE,
Method, Args,
false);
223 assert(ME->
isGLValue() &&
"Field member should be GL value");
225 assert(Dst &&
"Field member should have an origin list as it is GL value");
227 assert(Src &&
"Base expression should be a pointer/reference type");
243 {CE->getArgs(), CE->getNumArgs()});
252 MovedDecls.insert(DRE->getDecl());
270 case CK_LValueToRValue:
275 assert(Src &&
"LValue being cast to RValue has no origin list");
283 case CK_NullToPointer:
284 getOriginsList(*ICE);
288 case CK_ConstructorConversion:
289 case CK_UserDefinedConversion:
290 flow(Dest, Src,
true);
292 case CK_UncheckedDerivedToBase:
293 case CK_DerivedToBase:
297 flow(Dest, Src,
true);
299 case CK_FunctionToPointerDecay:
300 case CK_BuiltinFnToFnPtr:
301 case CK_ArrayToPointerDecay:
317 killAndFlowOrigin(*UO, *SubExpr);
322 killAndFlowOrigin(*UO, *SubExpr);
332 if (
OriginList *List = getOriginsList(*RetExpr))
335 L->getOuterOriginID(), RetExpr));
339void FactsGenerator::handleAssignment(
const Expr *LHSExpr,
340 const Expr *RHSExpr) {
344 if (
const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
345 LHSList = getOriginsList(*DRE_LHS);
346 assert(LHSList &&
"LHS is a DRE and should have an origin list");
351 if (
const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
352 LHSList = getOriginsList(*ME_LHS);
353 assert(LHSList &&
"LHS is a MemberExpr and should have an origin list");
357 OriginList *RHSList = getOriginsList(*RHSExpr);
365 if (
const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
366 markUseAsWrite(DRE_LHS);
406 if (handleTestPoint(FCE))
418 killAndFlowOrigin(*ILE, *ILE->
getInit(0));
433 assert((!SubExprList ||
435 "MTE top level origin should contain a loan to the MTE itself");
438 flow(RValMTEList, SubExprList,
true);
443 CurrentBlockFacts.push_back(
448void FactsGenerator::handleLifetimeEnds(
const CFGLifetimeEnds &LifetimeEnds) {
455 if (
const auto *BL = dyn_cast<PathLoan>(
Loan)) {
459 if (MovedDecls.contains(BL->getAccessPath().getAsValueDecl()))
465 if (Path == LifetimeEndsVD)
472void FactsGenerator::handleTemporaryDtor(
473 const CFGTemporaryDtor &TemporaryDtor) {
474 const CXXBindTemporaryExpr *ExpiringBTE =
475 TemporaryDtor.getBindTemporaryExpr();
480 if (
const auto *PL = dyn_cast<PathLoan>(Loan)) {
483 const AccessPath &AP = PL->getAccessPath();
484 const MaterializeTemporaryExpr *Path = AP.getAsMaterializeTemporaryExpr();
488 CurrentBlockFacts.push_back(FactMgr.
createFact<ExpireFact>(
489 PL->getID(), TemporaryDtor.getBindTemporaryExpr()->getEndLoc()));
495void FactsGenerator::handleExitBlock() {
497 for (
const Origin &O : FactMgr.getOriginMgr().getOrigins())
498 if (
auto *FD = dyn_cast_if_present<FieldDecl>(O.getDecl()))
499 EscapesInCurrentBlock.push_back(
500 FactMgr.createFact<FieldEscapeFact>(O.ID, FD));
503void FactsGenerator::handleGSLPointerConstruction(
const CXXConstructExpr *CCE) {
505 if (CCE->getNumArgs() != 1)
508 const Expr *Arg = CCE->getArg(0);
510 OriginList *ArgList = getOriginsList(*Arg);
511 assert(ArgList &&
"GSL pointer argument should have an origin list");
517 flow(getOriginsList(*CCE), ArgList,
true);
518 }
else if (Arg->getType()->isPointerType()) {
523 OriginList *ArgList = getOriginsList(*Arg);
524 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
525 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
530 handleFunctionCall(CCE, CCE->getConstructor(),
531 {CCE->getArgs(), CCE->getNumArgs()},
540void FactsGenerator::handleFunctionCall(
const Expr *
Call,
541 const FunctionDecl *FD,
542 ArrayRef<const Expr *> Args,
543 bool IsGslConstruction) {
544 OriginList *CallList = getOriginsList(*
Call);
547 if (!FD || !CallList)
549 auto IsArgLifetimeBound = [FD](
unsigned I) ->
bool {
550 const ParmVarDecl *PVD =
nullptr;
551 if (
const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
558 if ((I - 1) <
Method->getNumParams())
561 PVD =
Method->getParamDecl(I - 1);
564 }
else if (I < FD->getNumParams()) {
566 PVD = FD->getParamDecl(I);
568 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() :
false;
570 auto shouldTrackPointerImplicitObjectArg = [FD](
unsigned I) ->
bool {
571 const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
582 for (
unsigned I = 0; I < Args.size(); ++I) {
583 OriginList *ArgList = getOriginsList(*Args[I]);
586 if (IsGslConstruction) {
590 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
596 flow(CallList, ArgList, KillSrc);
599 }
else if (shouldTrackPointerImplicitObjectArg(I)) {
600 assert(ArgList->getLength() >= 2 &&
601 "Object arg of pointer type should have atleast two origins");
603 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
604 CallList->getOuterOriginID(),
605 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
607 }
else if (IsArgLifetimeBound(I)) {
611 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
612 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
620bool FactsGenerator::handleTestPoint(
const CXXFunctionalCastExpr *FCE) {
621 if (!FCE->getType()->isVoidType())
624 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
625 if (
const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
626 llvm::StringRef LiteralValue = SL->getString();
627 const std::string Prefix =
"__lifetime_test_point_";
629 if (LiteralValue.starts_with(Prefix)) {
630 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
631 CurrentBlockFacts.push_back(
632 FactMgr.createFact<TestPointFact>(Annotation));
642void FactsGenerator::handleUse(
const DeclRefExpr *DRE) {
643 OriginList *List = getOriginsList(*DRE);
648 if (!DRE->getDecl()->getType()->isReferenceType())
653 UseFact *UF = FactMgr.createFact<UseFact>(DRE, List);
654 CurrentBlockFacts.push_back(UF);
655 assert(!UseFacts.contains(DRE));
659void FactsGenerator::markUseAsWrite(
const DeclRefExpr *DRE) {
660 if (UseFacts.contains(DRE))
661 UseFacts[DRE]->markAsWritten();
666llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
667 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
671 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
672 if (
const auto *MD = dyn_cast<CXXMethodDecl>(FD); MD && MD->isInstance()) {
673 OriginList *List = *FactMgr.getOriginMgr().getThisOrigins();
674 const PlaceholderLoan *L =
675 FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(MD);
676 PlaceholderLoanFacts.push_back(
677 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
679 for (
const ParmVarDecl *PVD : FD->parameters()) {
680 OriginList *List = getOriginsList(*PVD);
683 const PlaceholderLoan *L =
684 FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(PVD);
685 PlaceholderLoanFacts.push_back(
686 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
688 return PlaceholderLoanFacts;
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 C++ object destructor implicitly generated at the end of full expression for temporary obj...
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.
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.
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 isInStdNamespace() const
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.
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point.
Represents a member of a struct/union/class.
Represents a function declaration or definition.
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
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
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.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
RetTy Visit(PTR(Stmt) S, ParamTys... P)
SourceLocation getEndLoc() const LLVM_READONLY
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.
FactType * createFact(Args &&...args)
LoanManager & getLoanMgr()
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 VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N)
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE)
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)
llvm::ArrayRef< const Loan * > getLoans() const
LoanType * createLoan(Args &&...args)
An abstract base class for a single "Loan" which represents lending a storage in memory.
A list of origins representing levels of indirection for pointer-like types.
OriginID getOuterOriginID() const
OriginList * peelOuterOrigin() const
PathLoan represents lending a storage location that is visible within the function's scope (e....
Represents that an origin escapes via a return statement.
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.
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...
static bool isStdMove(const FunctionDecl *FD)
bool doesDeclHaveStorage(const ValueDecl *D)
Returns true if the declaration has its own storage that can be borrowed.
bool hasOrigins(QualType QT)
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)
Represents the storage location being borrowed, e.g., a specific stack variable.
const clang::ValueDecl * getAsValueDecl() const