22#include "llvm/ADT/ArrayRef.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/Support/Casting.h"
25#include "llvm/Support/Signals.h"
26#include "llvm/Support/TimeProfiler.h"
29using llvm::isa_and_present;
31OriginList *FactsGenerator::getOriginsList(
const ValueDecl &D) {
32 return FactMgr.getOriginMgr().getOrCreateList(&D);
34OriginList *FactsGenerator::getOriginsList(
const Expr &E) {
35 return FactMgr.getOriginMgr().getOrCreateList(&E);
55 "Dst is non-null but Src is null. List must have the same length");
56 assert(Dst->getLength() == Src->getLength() &&
57 "Lists must have the same length");
60 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
61 Dst->getOuterOriginID(), Src->getOuterOriginID(), Kill));
62 Dst = Dst->peelOuterOrigin();
63 Src = Src->peelOuterOrigin();
73 if (
const auto *VD = dyn_cast<ValueDecl>(DRE->
getDecl())) {
91 llvm::TimeTraceScope TimeProfile(
"FactGenerator");
92 const CFG &Cfg = *AC.getCFG();
97 CurrentBlockFacts.clear();
98 EscapesInCurrentBlock.clear();
100 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
101 PlaceholderLoanFacts.end());
102 for (
unsigned I = 0; I <
Block->size(); ++I) {
104 if (std::optional<CFGStmt> CS = Element.
getAs<
CFGStmt>())
105 Visit(CS->getStmt());
106 else if (std::optional<CFGInitializer>
Initializer =
108 handleCXXCtorInitializer(
Initializer->getInitializer());
109 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
111 handleLifetimeEnds(*LifetimeEnds);
112 else if (std::optional<CFGFullExprCleanup> FullExprCleanup =
114 handleFullExprCleanup(*FullExprCleanup);
120 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
121 EscapesInCurrentBlock.end());
122 FactMgr.addBlockFacts(
Block, CurrentBlockFacts);
141 if (
const auto *VD = dyn_cast<VarDecl>(D))
142 if (
const Expr *InitExpr = VD->getInit()) {
146 OriginList *InitList = getOriginsList(*InitExpr);
147 assert(InitList &&
"VarDecl had origins but InitExpr did not");
148 flow(VDList, InitList,
true);
171 "gl-value DRE of non-pointer type should have an origin list");
174 CurrentBlockFacts.push_back(
181 handleGSLPointerConstruction(CCE);
185 {CCE->getArgs(), CCE->getNumArgs()},
193 killAndFlowOrigin(*FD, *CII->
getInit());
204 {MCE->getImplicitObjectArgument()},
215 handleFunctionCall(MCE,
Method, Args,
false);
222 assert(ME->
isGLValue() &&
"Field member should be GL value");
224 assert(Dst &&
"Field member should have an origin list as it is GL value");
226 assert(Src &&
"Base expression should be a pointer/reference type");
237 {CE->getArgs(), CE->getNumArgs()});
255 case CK_LValueToRValue:
260 assert(Src &&
"LValue being cast to RValue has no origin list");
268 case CK_NullToPointer:
269 getOriginsList(*ICE);
273 case CK_ConstructorConversion:
274 case CK_UserDefinedConversion:
275 flow(Dest, Src,
true);
277 case CK_UncheckedDerivedToBase:
278 case CK_DerivedToBase:
282 flow(Dest, Src,
true);
284 case CK_FunctionToPointerDecay:
285 case CK_BuiltinFnToFnPtr:
286 case CK_ArrayToPointerDecay:
302 killAndFlowOrigin(*UO, *SubExpr);
307 killAndFlowOrigin(*UO, *SubExpr);
317 if (
OriginList *List = getOriginsList(*RetExpr))
320 L->getOuterOriginID(), RetExpr));
324void FactsGenerator::handleAssignment(
const Expr *LHSExpr,
325 const Expr *RHSExpr) {
329 if (
const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
330 LHSList = getOriginsList(*DRE_LHS);
331 assert(LHSList &&
"LHS is a DRE and should have an origin list");
336 if (
const auto *ME_LHS = dyn_cast<MemberExpr>(LHSExpr)) {
337 LHSList = getOriginsList(*ME_LHS);
338 assert(LHSList &&
"LHS is a MemberExpr and should have an origin list");
342 OriginList *RHSList = getOriginsList(*RHSExpr);
350 if (
const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
351 markUseAsWrite(DRE_LHS);
392 if (handleTestPoint(FCE))
404 killAndFlowOrigin(*ILE, *ILE->
getInit(0));
419 assert((!SubExprList ||
421 "MTE top level origin should contain a loan to the MTE itself");
424 flow(RValMTEList, SubExprList,
true);
429 CurrentBlockFacts.push_back(
434void FactsGenerator::handleLifetimeEnds(
const CFGLifetimeEnds &LifetimeEnds) {
440 if (
const auto *BL = dyn_cast<PathLoan>(
Loan)) {
445 if (Path == LifetimeEndsVD)
452void FactsGenerator::handleFullExprCleanup(
453 const CFGFullExprCleanup &FullExprCleanup) {
456 if (
const auto *PL = dyn_cast<PathLoan>(Loan)) {
459 const AccessPath &AP = PL->getAccessPath();
460 const MaterializeTemporaryExpr *Path = AP.getAsMaterializeTemporaryExpr();
463 if (llvm::is_contained(FullExprCleanup.getExpiringMTEs(), Path)) {
464 CurrentBlockFacts.push_back(
465 FactMgr.
createFact<ExpireFact>(PL->getID(), Path->getEndLoc()));
471void FactsGenerator::handleExitBlock() {
473 for (
const Origin &O : FactMgr.getOriginMgr().getOrigins())
474 if (
auto *FD = dyn_cast_if_present<FieldDecl>(O.getDecl()))
475 EscapesInCurrentBlock.push_back(
476 FactMgr.createFact<FieldEscapeFact>(O.ID, FD));
479void FactsGenerator::handleGSLPointerConstruction(
const CXXConstructExpr *CCE) {
481 if (CCE->getNumArgs() != 1)
484 const Expr *Arg = CCE->getArg(0);
486 OriginList *ArgList = getOriginsList(*Arg);
487 assert(ArgList &&
"GSL pointer argument should have an origin list");
493 flow(getOriginsList(*CCE), ArgList,
true);
494 }
else if (Arg->getType()->isPointerType()) {
499 OriginList *ArgList = getOriginsList(*Arg);
500 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
501 getOriginsList(*CCE)->getOuterOriginID(), ArgList->getOuterOriginID(),
506 handleFunctionCall(CCE, CCE->getConstructor(),
507 {CCE->getArgs(), CCE->getNumArgs()},
512void FactsGenerator::handleMovedArgsInCall(
const FunctionDecl *FD,
513 ArrayRef<const Expr *> Args) {
514 unsigned IsInstance = 0;
515 if (
const auto *MD = dyn_cast<CXXMethodDecl>(FD);
522 const Expr *UniquePtrExpr = Args[0];
523 OriginList *MovedOrigins = getOriginsList(*UniquePtrExpr);
525 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
526 UniquePtrExpr, MovedOrigins->getOuterOriginID()));
531 for (
unsigned I = IsInstance;
532 I < Args.size() && I < FD->getNumParams() + IsInstance; ++I) {
533 const ParmVarDecl *PVD = FD->getParamDecl(I - IsInstance);
534 if (!PVD->getType()->isRValueReferenceType())
536 const Expr *Arg = Args[I];
537 OriginList *MovedOrigins = getOriginsList(*Arg);
538 assert(MovedOrigins->getLength() >= 1 &&
539 "unexpected length for r-value reference param");
541 CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
542 Arg, MovedOrigins->getOuterOriginID()));
546void FactsGenerator::handleInvalidatingCall(
const Expr *
Call,
547 const FunctionDecl *FD,
548 ArrayRef<const Expr *> Args) {
549 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
550 if (!MD || !MD->isInstance())
556 auto *DRE = dyn_cast<DeclRefExpr>(Args[0]);
557 if (!DRE || DRE->getDecl()->getType()->isReferenceType())
560 OriginList *ThisList = getOriginsList(*Args[0]);
562 CurrentBlockFacts.push_back(FactMgr.createFact<InvalidateOriginFact>(
563 ThisList->getOuterOriginID(),
Call));
566void FactsGenerator::handleFunctionCall(
const Expr *
Call,
567 const FunctionDecl *FD,
568 ArrayRef<const Expr *> Args,
569 bool IsGslConstruction) {
570 OriginList *CallList = getOriginsList(*
Call);
576 for (
const Expr *Arg : Args)
578 handleInvalidatingCall(
Call, FD, Args);
579 handleMovedArgsInCall(FD, Args);
582 auto IsArgLifetimeBound = [FD](
unsigned I) ->
bool {
583 const ParmVarDecl *PVD =
nullptr;
584 if (
const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
591 if ((I - 1) <
Method->getNumParams())
594 PVD =
Method->getParamDecl(I - 1);
597 }
else if (I < FD->getNumParams()) {
599 PVD = FD->getParamDecl(I);
601 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() :
false;
603 auto shouldTrackPointerImplicitObjectArg = [FD](
unsigned I) ->
bool {
604 const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
615 for (
unsigned I = 0; I < Args.size(); ++I) {
616 OriginList *ArgList = getOriginsList(*Args[I]);
619 if (IsGslConstruction) {
623 assert(!Args[I]->isGLValue() || ArgList->getLength() >= 2);
629 flow(CallList, ArgList, KillSrc);
632 }
else if (shouldTrackPointerImplicitObjectArg(I)) {
633 assert(ArgList->getLength() >= 2 &&
634 "Object arg of pointer type should have atleast two origins");
636 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
637 CallList->getOuterOriginID(),
638 ArgList->peelOuterOrigin()->getOuterOriginID(), KillSrc));
640 }
else if (IsArgLifetimeBound(I)) {
644 CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
645 CallList->getOuterOriginID(), ArgList->getOuterOriginID(), KillSrc));
653bool FactsGenerator::handleTestPoint(
const CXXFunctionalCastExpr *FCE) {
654 if (!FCE->getType()->isVoidType())
657 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
658 if (
const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
659 llvm::StringRef LiteralValue = SL->getString();
660 const std::string Prefix =
"__lifetime_test_point_";
662 if (LiteralValue.starts_with(Prefix)) {
663 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
664 CurrentBlockFacts.push_back(
665 FactMgr.createFact<TestPointFact>(Annotation));
672void FactsGenerator::handleUse(
const Expr *E) {
673 OriginList *List = getOriginsList(*E);
679 if (
auto *DRE = dyn_cast<DeclRefExpr>(E);
680 DRE && !DRE->getDecl()->
getType()->isReferenceType())
685 if (!UseFacts.contains(E)) {
686 UseFact *UF = FactMgr.createFact<UseFact>(E, List);
687 CurrentBlockFacts.push_back(UF);
692void FactsGenerator::markUseAsWrite(
const DeclRefExpr *DRE) {
693 if (UseFacts.contains(DRE))
694 UseFacts[DRE]->markAsWritten();
699llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
700 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
704 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
705 if (
auto ThisOrigins = FactMgr.getOriginMgr().getThisOrigins()) {
706 OriginList *List = *ThisOrigins;
707 const PlaceholderLoan *L = FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(
709 PlaceholderLoanFacts.push_back(
710 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
712 for (
const ParmVarDecl *PVD : FD->parameters()) {
713 OriginList *List = getOriginsList(*PVD);
716 const PlaceholderLoan *L =
717 FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(PVD);
718 PlaceholderLoanFacts.push_back(
719 FactMgr.createFact<IssueFact>(L->getID(), List->getOuterOriginID()));
721 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.
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.
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
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 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
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
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.
const clang::ValueDecl * getAsValueDecl() const
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 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...
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 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)