17#include "llvm/Support/Casting.h"
18#include "llvm/Support/Signals.h"
19#include "llvm/Support/TimeProfiler.h"
22using llvm::isa_and_present;
24OriginList *FactsGenerator::getOriginsList(
const ValueDecl &D) {
25 return FactMgr.getOriginMgr().getOrCreateList(&D);
27OriginList *FactsGenerator::getOriginsList(
const Expr &E) {
28 return FactMgr.getOriginMgr().getOrCreateList(&E);
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");
53 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
54 Dst->getOuterOriginID(), Src->getOuterOriginID(), Kill));
55 Dst = Dst->peelOuterOrigin();
56 Src = Src->peelOuterOrigin();
66 if (
const auto *VD = dyn_cast<ValueDecl>(DRE->
getDecl())) {
91 return dyn_cast<CXXBindTemporaryExpr>(Child);
95 llvm::TimeTraceScope TimeProfile(
"FactGenerator");
96 const CFG &Cfg = *AC.getCFG();
101 CurrentBlockFacts.clear();
102 EscapesInCurrentBlock.clear();
104 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
105 PlaceholderLoanFacts.end());
106 for (
unsigned I = 0; I <
Block->size(); ++I) {
108 if (std::optional<CFGStmt> CS = Element.
getAs<
CFGStmt>())
109 Visit(CS->getStmt());
110 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
112 handleLifetimeEnds(*LifetimeEnds);
113 else if (std::optional<CFGTemporaryDtor> TemporaryDtor =
115 handleTemporaryDtor(*TemporaryDtor);
117 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
118 EscapesInCurrentBlock.end());
119 FactMgr.addBlockFacts(
Block, CurrentBlockFacts);
138 if (
const auto *VD = dyn_cast<VarDecl>(D))
139 if (
const Expr *InitExpr = VD->getInit()) {
143 OriginList *InitList = getOriginsList(*InitExpr);
144 assert(InitList &&
"VarDecl had origins but InitExpr did not");
145 flow(VDList, InitList,
true);
168 "gl-value DRE of non-pointer type should have an origin list");
171 CurrentBlockFacts.push_back(
178 handleGSLPointerConstruction(CCE);
191 {MCE->getImplicitObjectArgument()},
202 handleFunctionCall(MCE,
Method, Args,
false);
209 assert(ME->
isGLValue() &&
"Field member should be GL value");
211 assert(Dst &&
"Field member should have an origin list as it is GL value");
213 assert(Src &&
"Base expression should be a pointer/reference type");
229 {CE->getArgs(), CE->getNumArgs()});
238 MovedDecls.insert(DRE->getDecl());
256 case CK_LValueToRValue:
261 assert(Src &&
"LValue being cast to RValue has no origin list");
269 case CK_NullToPointer:
270 getOriginsList(*ICE);
274 case CK_ConstructorConversion:
275 case CK_UserDefinedConversion:
276 flow(Dest, Src,
true);
278 case CK_UncheckedDerivedToBase:
279 case CK_DerivedToBase:
283 flow(Dest, Src,
true);
285 case CK_FunctionToPointerDecay:
286 case CK_BuiltinFnToFnPtr:
287 case CK_ArrayToPointerDecay:
303 killAndFlowOrigin(*UO, *SubExpr);
308 killAndFlowOrigin(*UO, *SubExpr);
318 if (
OriginList *List = getOriginsList(*RetExpr))
321 L->getOuterOriginID(), RetExpr));
325void FactsGenerator::handleAssignment(
const Expr *LHSExpr,
326 const Expr *RHSExpr) {
327 if (
const auto *DRE_LHS =
329 OriginList *LHSList = getOriginsList(*DRE_LHS);
330 assert(LHSList &&
"LHS is a DRE and should have an origin list");
331 OriginList *RHSList = getOriginsList(*RHSExpr);
340 markUseAsWrite(DRE_LHS);
381 if (handleTestPoint(FCE))
393 killAndFlowOrigin(*ILE, *ILE->
getInit(0));
406 assert((!SubExprList ||
408 "MTE top level origin should contain a loan to the MTE itself");
414 CurrentBlockFacts.push_back(
417 flow(MTEList, SubExprList,
true);
420void FactsGenerator::handleLifetimeEnds(
const CFGLifetimeEnds &LifetimeEnds) {
427 if (
const auto *BL = dyn_cast<PathLoan>(
Loan)) {
431 if (MovedDecls.contains(BL->getAccessPath().getAsValueDecl()))
437 if (Path == LifetimeEndsVD)
444void FactsGenerator::handleTemporaryDtor(
445 const CFGTemporaryDtor &TemporaryDtor) {
446 const CXXBindTemporaryExpr *ExpiringBTE =
447 TemporaryDtor.getBindTemporaryExpr();
452 if (
const auto *PL = dyn_cast<PathLoan>(Loan)) {
455 const AccessPath &AP = PL->getAccessPath();
456 const MaterializeTemporaryExpr *Path = AP.getAsMaterializeTemporaryExpr();
460 CurrentBlockFacts.push_back(FactMgr.
createFact<ExpireFact>(
461 PL->getID(), TemporaryDtor.getBindTemporaryExpr()->getEndLoc()));
467void FactsGenerator::handleGSLPointerConstruction(
const CXXConstructExpr *CCE) {
469 if (CCE->getNumArgs() != 1)
472 const Expr *Arg = CCE->getArg(0);
474 OriginList *ArgList = getOriginsList(*Arg);
475 assert(ArgList &&
"GSL pointer argument should have an origin list");
481 flow(getOriginsList(*CCE), ArgList,
true);
482 }
else if (Arg->getType()->isPointerType()) {
487 OriginList *ArgList = getOriginsList(*Arg);
488 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
489 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
494 handleFunctionCall(CCE, CCE->getConstructor(),
495 {CCE->getArgs(), CCE->getNumArgs()},
504void FactsGenerator::handleFunctionCall(
const Expr *
Call,
505 const FunctionDecl *FD,
506 ArrayRef<const Expr *> Args,
507 bool IsGslConstruction) {
508 OriginList *CallList = getOriginsList(*
Call);
511 if (!FD || !CallList)
513 auto IsArgLifetimeBound = [FD](
unsigned I) ->
bool {
514 const ParmVarDecl *PVD =
nullptr;
515 if (
const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
522 if ((I - 1) <
Method->getNumParams())
525 PVD =
Method->getParamDecl(I - 1);
528 }
else if (I < FD->getNumParams()) {
530 PVD = FD->getParamDecl(I);
532 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() :
false;
534 auto shouldTrackPointerImplicitObjectArg = [FD](
unsigned I) ->
bool {
535 const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
546 for (
unsigned I = 0; I < Args.size(); ++I) {
547 OriginList *ArgList = getOriginsList(*Args[I]);
550 if (IsGslConstruction) {
554 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
560 flow(CallList, ArgList, KillSrc);
563 }
else if (shouldTrackPointerImplicitObjectArg(I)) {
564 assert(ArgList->getLength() >= 2 &&
565 "Object arg of pointer type should have atleast two origins");
567 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
568 CallList->getOuterOriginID(),
569 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
571 }
else if (IsArgLifetimeBound(I)) {
575 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
576 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
584bool FactsGenerator::handleTestPoint(
const CXXFunctionalCastExpr *FCE) {
585 if (!FCE->getType()->isVoidType())
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_";
593 if (LiteralValue.starts_with(Prefix)) {
594 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
595 CurrentBlockFacts.push_back(
596 FactMgr.createFact<TestPointFact>(Annotation));
606void FactsGenerator::handleUse(
const DeclRefExpr *DRE) {
607 OriginList *List = getOriginsList(*DRE);
612 if (!DRE->getDecl()->getType()->isReferenceType())
617 UseFact *UF = FactMgr.createFact<UseFact>(DRE, List);
618 CurrentBlockFacts.push_back(UF);
619 assert(!UseFacts.contains(DRE));
623void FactsGenerator::markUseAsWrite(
const DeclRefExpr *DRE) {
624 if (UseFacts.contains(DRE))
625 UseFacts[DRE]->markAsWritten();
630llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
631 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
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()));
643 for (
const ParmVarDecl *PVD : FD->parameters()) {
644 OriginList *List = getOriginsList(*PVD);
647 const PlaceholderLoan *L =
648 FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(PVD);
649 PlaceholderLoanFacts.push_back(
650 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
652 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 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.
Represents a call to a C++ constructor.
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 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.
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.
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)
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....
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.
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)
@ SD_FullExpression
Full-expression storage duration (for temporaries).
Represents the storage location being borrowed, e.g., a specific stack variable.
const clang::ValueDecl * getAsValueDecl() const