12#include "llvm/Support/Casting.h"
13#include "llvm/Support/TimeProfiler.h"
16using llvm::isa_and_present;
36 if (
const auto *VD = dyn_cast<ValueDecl>(DRE->
getDecl())) {
45 llvm::TimeTraceScope TimeProfile(
"FactGenerator");
46 const CFG &Cfg = *AC.getCFG();
51 CurrentBlockFacts.clear();
52 EscapesInCurrentBlock.clear();
54 CurrentBlockFacts.append(PlaceholderLoanFacts.begin(),
55 PlaceholderLoanFacts.end());
56 for (
unsigned I = 0; I <
Block->size(); ++I) {
58 if (std::optional<CFGStmt> CS = Element.
getAs<
CFGStmt>())
60 else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
62 handleLifetimeEnds(*LifetimeEnds);
64 CurrentBlockFacts.append(EscapesInCurrentBlock.begin(),
65 EscapesInCurrentBlock.end());
66 FactMgr.addBlockFacts(
Block, CurrentBlockFacts);
72 if (
const auto *VD = dyn_cast<VarDecl>(D))
74 if (
const Expr *InitExpr = VD->getInit())
75 killAndFlowOrigin(*VD, *InitExpr);
92 OriginID ExprOID = FactMgr.getOriginMgr().getOrCreate(*DRE);
93 CurrentBlockFacts.push_back(
94 FactMgr.createFact<
IssueFact>(L->getID(), ExprOID));
101 handleGSLPointerConstruction(CCE);
113 {MCE->getImplicitObjectArgument()},
123 handleFunctionCall(MCE,
Method, Args,
false);
129 {CE->getArgs(), CE->getNumArgs()});
136 FactMgr.getOriginMgr().getOrCreate(*N);
158 killAndFlowOrigin(*UO, *SubExpr);
165 OriginID OID = FactMgr.getOriginMgr().getOrCreate(*RetExpr);
166 EscapesInCurrentBlock.push_back(
194 {OCE->getArgs(), OCE->getNumArgs()},
202 if (handleTestPoint(FCE))
214 killAndFlowOrigin(*ILE, *ILE->
getInit(0));
226void FactsGenerator::handleLifetimeEnds(
const CFGLifetimeEnds &LifetimeEnds) {
233 if (
const auto *BL = dyn_cast<PathLoan>(
Loan)) {
236 if (BL->getAccessPath().D == LifetimeEndsVD)
243void FactsGenerator::handleGSLPointerConstruction(
const CXXConstructExpr *CCE) {
245 if (CCE->getNumArgs() != 1)
248 killAndFlowOrigin(*CCE, *CCE->getArg(0));
251 handleFunctionCall(CCE, CCE->getConstructor(),
252 {CCE->getArgs(), CCE->getNumArgs()},
260void FactsGenerator::handleFunctionCall(
const Expr *
Call,
261 const FunctionDecl *FD,
262 ArrayRef<const Expr *> Args,
263 bool IsGslConstruction) {
267 auto IsArgLifetimeBound = [FD](
unsigned I) ->
bool {
268 const ParmVarDecl *PVD =
nullptr;
269 if (
const auto *
Method = dyn_cast<CXXMethodDecl>(FD);
274 if ((I - 1) <
Method->getNumParams())
277 PVD =
Method->getParamDecl(I - 1);
278 }
else if (I < FD->getNumParams())
280 PVD = FD->getParamDecl(I);
281 return PVD ? PVD->hasAttr<clang::LifetimeBoundAttr>() :
false;
285 bool killedSrc =
false;
286 for (
unsigned I = 0; I < Args.size(); ++I)
287 if (IsGslConstruction || IsArgLifetimeBound(I)) {
290 killAndFlowOrigin(*
Call, *Args[I]);
292 flowOrigin(*
Call, *Args[I]);
298bool FactsGenerator::handleTestPoint(
const CXXFunctionalCastExpr *FCE) {
299 if (!FCE->getType()->isVoidType())
302 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
303 if (
const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
304 llvm::StringRef LiteralValue = SL->getString();
305 const std::string Prefix =
"__lifetime_test_point_";
307 if (LiteralValue.starts_with(Prefix)) {
308 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
309 CurrentBlockFacts.push_back(
310 FactMgr.createFact<TestPointFact>(Annotation));
317void FactsGenerator::handleAssignment(
const Expr *LHSExpr,
318 const Expr *RHSExpr) {
322 if (
const auto *DRE_LHS =
323 dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts())) {
324 markUseAsWrite(DRE_LHS);
325 if (
const auto *VD_LHS = dyn_cast<ValueDecl>(DRE_LHS->getDecl())) {
328 killAndFlowOrigin(*VD_LHS, *RHSExpr);
336void FactsGenerator::handleUse(
const DeclRefExpr *DRE) {
338 UseFact *UF = FactMgr.createFact<UseFact>(DRE, FactMgr.getOriginMgr());
339 CurrentBlockFacts.push_back(UF);
340 assert(!UseFacts.contains(DRE));
345void FactsGenerator::markUseAsWrite(
const DeclRefExpr *DRE) {
348 assert(UseFacts.contains(DRE));
349 UseFacts[DRE]->markAsWritten();
354llvm::SmallVector<Fact *> FactsGenerator::issuePlaceholderLoans() {
355 const auto *FD = dyn_cast<FunctionDecl>(AC.getDecl());
359 llvm::SmallVector<Fact *> PlaceholderLoanFacts;
360 for (
const ParmVarDecl *PVD : FD->parameters()) {
362 const PlaceholderLoan *L =
363 FactMgr.getLoanMgr().createLoan<PlaceholderLoan>(PVD);
364 OriginID OID = FactMgr.getOriginMgr().getOrCreate(*PVD);
365 PlaceholderLoanFacts.push_back(
366 FactMgr.createFact<IssueFact>(L->getID(), OID));
369 return PlaceholderLoanFacts;
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isAssignmentOp(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 a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
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.
static bool isAssignmentOp(OverloadedOperatorKind Opc)
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.
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.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
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.
A (possibly-)qualified type.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
RetTy Visit(PTR(Stmt) S, ParamTys... P)
SourceLocation getEndLoc() const LLVM_READONLY
bool isPointerOrReferenceType() const
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
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 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.
PathLoan represents lending a storage location that is visible within the function's scope (e....
static const PathLoan * createLoan(FactManager &FactMgr, const DeclRefExpr *DRE)
Creates a loan for the storage path of a given declaration reference.
static bool hasOrigin(const Expr *E)
utils::ID< struct OriginTag > OriginID
static bool isPointerType(QualType QT)
bool isGslPointerType(QualType QT)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
Represents the storage location being borrowed, e.g., a specific stack variable.