llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-analysis
Author: Gábor Horváth (Xazax-hun)
<details>
<summary>Changes</summary>
Previously every DeclRefExpr was a use, so naming a pointer, taking its address
or copying it counted as reading what it points to. Writes were then exempted
after the fact through a UseFact -> Expr map and a special case for writes
through references.
Now a use is an access: an lvalue-to-rvalue conversion, a write through an
assignment, increment or asm output, or a copy of a class object from a glvalue.
It is recorded on the accessed lvalue's outer origin, the loans saying which
storage it may name. The visitors for `*p`, `p->f` and `p[i]` already flow
the
base pointer there, so dereferences need no special handling. Reads of a value
go through readValue(), which records the access; writes peel the outer origin
directly. Values handed to opaque code still use every level.
Consequences:
- Copying a pointer, taking an address, `(void)p` and `p++` are not uses.
- Writing through a dangling pointer (`*p = 1`, `p->f = 1`) is now
diagnosed.
- An access of an origin that names a declaration outright is skipped: it
only holds a loan to that declaration, which is valid wherever it is named.
- UseFact::IsWritten and markUseAsWrite are removed; kills on assignment
already come from the destination's OriginFlowFact or KillOriginFact.
Fewer use facts are generated, e.g. on the lifetime-safety lit tests:
safety.cpp 1886 -> 882
invalidations.cpp 616 -> 451
nocfg.cpp 544 -> 415
capture-by.cpp 395 -> 324
Assisted by: Opus 5.5
---
Patch is 189.54 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/225799.diff
24 Files Affected:
- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h (-6)
- (modified)
clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h (+13-11)
- (modified)
clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h (+2)
- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
(+4)
- (modified) clang/lib/Analysis/LifetimeSafety/Checker.cpp (+15-6)
- (modified) clang/lib/Analysis/LifetimeSafety/Facts.cpp (+1-1)
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+87-92)
- (modified) clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp (+1-4)
- (modified) clang/lib/Analysis/LifetimeSafety/LiveOrigins.cpp (+5-13)
- (modified) clang/lib/Analysis/LifetimeSafety/Origins.cpp (+11-1)
- (modified) clang/test/Sema/LifetimeSafety/Inputs/lifetime-analysis.h (+5)
- (modified) clang/test/Sema/LifetimeSafety/annotation-suggestions.cpp (+7-7)
- (modified) clang/test/Sema/LifetimeSafety/capture-by.cpp (+66-66)
- (modified) clang/test/Sema/LifetimeSafety/cfg-bailout.cpp (+3-1)
- (modified) clang/test/Sema/LifetimeSafety/dangling-field.cpp (+18-3)
- (modified) clang/test/Sema/LifetimeSafety/dangling-global.cpp (+1-1)
- (modified) clang/test/Sema/LifetimeSafety/inapplicable-lifetimebound.cpp
(+1-1)
- (modified) clang/test/Sema/LifetimeSafety/invalidations.cpp (+37-37)
- (modified) clang/test/Sema/LifetimeSafety/lifetime-facts.cpp (+66-9)
- (modified) clang/test/Sema/LifetimeSafety/lifetimebound-violation.cpp (+1-1)
- (modified) clang/test/Sema/LifetimeSafety/nocfg.cpp (+2-3)
- (modified) clang/test/Sema/LifetimeSafety/noescape-violation.cpp (+1-1)
- (modified) clang/test/Sema/LifetimeSafety/safety.cpp (+528-209)
- (modified) clang/unittests/Analysis/LifetimeSafetyTest.cpp (+101-9)
``````````diff
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 794e0cd30b9e5f..16fe31a577fa1b 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -246,9 +246,6 @@ class GlobalEscapeFact : public OriginEscapesFact {
class UseFact : public Fact {
const Expr *UseExpr;
const OriginList *OList;
- // True if this use is a write operation (e.g., left-hand side of
assignment).
- // Write operations are exempted from use-after-free checks.
- bool IsWritten = false;
public:
static bool classof(const Fact *F) { return F->getKind() == Kind::Use; }
@@ -257,10 +254,7 @@ class UseFact : public Fact {
: Fact(Kind::Use), UseExpr(UseExpr), OList(OList) {}
const OriginList *getUsedOrigins() const { return OList; }
- void setUsedOrigins(const OriginList *NewList) { OList = NewList; }
const Expr *getUseExpr() const { return UseExpr; }
- void markAsWritten() { IsWritten = true; }
- bool isWritten() const { return IsWritten; }
void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager
&OM,
const LoanPropagationAnalysis *LPA = nullptr) const override;
diff --git
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index ec5027965002e4..e9f2a4789241c0 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -57,6 +57,9 @@ class FactsGenerator : public
ConstStmtVisitor<FactsGenerator> {
void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE);
void VisitCXXNewExpr(const CXXNewExpr *NE);
void VisitCXXDeleteExpr(const CXXDeleteExpr *DE);
+ void VisitCXXThrowExpr(const CXXThrowExpr *TE);
+ void VisitGCCAsmStmt(const GCCAsmStmt *AS);
+ void VisitCXXTypeidExpr(const CXXTypeidExpr *TE);
void VisitStmtExpr(const StmtExpr *SE);
private:
@@ -138,12 +141,17 @@ class FactsGenerator : public
ConstStmtVisitor<FactsGenerator> {
/// If so, creates a `TestPointFact` and returns true.
bool handleTestPoint(const CXXFunctionalCastExpr *FCE);
- // Treats an expression as a use of the referenced object. It will be
- // checked for use-after-free unless it is later marked as being written to
- // (e.g. on the left-hand side of an assignment in the case of a
DeclRefExpr).
- void handleUse(const Expr *E);
+ bool namesDeclStorage(const OriginList *List) const;
+
+ OriginList *readValue(const Expr *E);
- void markUseAsWrite(const DeclRefExpr *DRE);
+ /// Records an access (read or write) of the storage \p E designates, or that
+ /// a prvalue pointer \p E points to.
+ void handleAccess(const Expr *E);
+
+ /// Records that \p E's value is handed to opaque code, which may dereference
+ /// it to any depth.
+ void handleUse(const Expr *E);
bool escapesViaReturn(OriginID OID) const;
@@ -155,12 +163,6 @@ class FactsGenerator : public
ConstStmtVisitor<FactsGenerator> {
// appended at the end of CurrentBlockFacts to ensure they appear after
// ExpireFact entries.
llvm::SmallVector<Fact *> EscapesInCurrentBlock;
- // To distinguish between reads and writes for use-after-free checks, this
map
- // stores the `UseFact` for each `DeclRefExpr`. We initially identify all
- // `DeclRefExpr`s as "read" uses. When an assignment is processed, the use
- // corresponding to the left-hand side is updated to be a "write", thereby
- // exempting it from the check.
- llvm::DenseMap<const Expr *, UseFact *> UseFacts;
const CFGBlock *CurrentBlock;
bool IsCMode = false;
};
diff --git
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 68e84961010ddf..18e5e8473e4144 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -74,6 +74,8 @@ class LifetimeSafetySemaHelper {
SourceLocation FreeLoc,
llvm::ArrayRef<const Expr *> ExprChain) {}
+ // TODO: Pass the expiry location and aliasing chain like
+ // reportUseAfterScope.
virtual void reportUseAfterReturn(const Expr *IssueExpr,
const Expr *ReturnExpr,
const Expr *MovedExpr) {}
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
index 6ab2f59283ad3c..b4a7ec2832d712 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h
@@ -53,6 +53,10 @@ struct Origin {
/// Null for synthetic lvalue origins (e.g., outer origin of DeclRefExpr).
const Type *Ty;
+ /// True if this origin only holds a loan to a declaration named in scope, so
+ /// it can never hold an expired loan.
+ bool NamesDeclStorage = false;
+
Origin(OriginID ID, const clang::ValueDecl *D, const Type *QT)
: ID(ID), Ptr(D), Ty(QT) {}
Origin(OriginID ID, const clang::Expr *E, const Type *QT)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index c4cc872dcd568d..a590491df23e74 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -24,6 +24,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
@@ -557,14 +558,22 @@ class LifetimeChecker {
/// Given a chain of origins that shows how a loan propagates, this function
/// extracts the corresponding expressions for each origin. Origins that
refer
/// to declarations (rather than expressions) are skipped.
+ ///
+ /// Until the chain reaches a declaration it is inside the use expression,
+ /// where casts just load the used variable.
llvm::SmallVector<const Expr *>
getExprChain(llvm::ArrayRef<OriginID> OriginFlowChain) {
- llvm::SmallVector<const Expr *> rs;
- for (const OriginID CurrOID : OriginFlowChain)
- if (const Expr *CurrExpr =
- FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr())
- rs.push_back(CurrExpr);
- return rs;
+ llvm::SmallVector<const Expr *> Chain;
+ bool InUse = true;
+ for (const OriginID CurrOID : OriginFlowChain) {
+ const Expr *CurrExpr =
+ FactMgr.getOriginMgr().getOrigin(CurrOID).getExpr();
+ if (!CurrExpr)
+ InUse = false;
+ else if (!InUse || !isa<ImplicitCastExpr>(CurrExpr))
+ Chain.push_back(CurrExpr);
+ }
+ return Chain;
}
};
} // namespace
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index a56774327731c2..2d3c161ae8f113 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -167,7 +167,7 @@ void UseFact::dump(llvm::raw_ostream &OS, const LoanManager
&,
if (I < NumUsedOrigins - 1)
OS << ", ";
}
- OS << ", " << (isWritten() ? "Write" : "Read") << ")\n";
+ OS << ")\n";
}
void InvalidateOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &,
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 98760dba188821..091935df1a509e 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -153,17 +153,17 @@ void FactsGenerator::run() {
FactMgr.computePersistentOrigins(Cfg);
}
-/// Simulates LValueToRValue conversion by peeling the outer lvalue origin
-/// if the expression is a GLValue. For pointer/view GLValues, this strips
-/// the origin representing the storage location to get the origins of the
-/// pointed-to value.
+/// Returns the origins of the value \p E evaluates to, recording the read of a
+/// glvalue. Writes peel the outer origin directly instead.
///
/// Example: For `View& v`, returns the origin of what v points to, not v's
/// storage.
-static OriginList *getRValueOrigins(const Expr *E, OriginList *List) {
- if (!List)
- return nullptr;
- return E->isGLValue() ? List->peelOuterOrigin() : List;
+OriginList *FactsGenerator::readValue(const Expr *E) {
+ OriginList *List = getOriginsList(*E);
+ if (!E->isGLValue())
+ return List;
+ handleAccess(E);
+ return List ? List->peelOuterOrigin() : nullptr;
}
void FactsGenerator::VisitDeclStmt(const DeclStmt *DS) {
@@ -184,7 +184,6 @@ void FactsGenerator::VisitDeclRefExpr(const DeclRefExpr
*DRE) {
// GLValues (like EnumConstants).
if (DRE->getFoundDecl()->isFunctionOrFunctionTemplate() || !DRE->isGLValue())
return;
- handleUse(DRE);
// For all declarations with storage (non-references), we issue a loan
// representing the borrow of the variable's storage itself.
//
@@ -218,7 +217,7 @@ void FactsGenerator::VisitCXXConstructExpr(const
CXXConstructExpr *CCE) {
CCE->getConstructor()->isDefaulted() && CCE->getNumArgs() == 1 &&
hasOrigins(CCE->getType())) {
const Expr *Arg = CCE->getArg(0);
- if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
+ if (OriginList *ArgList = readValue(Arg)) {
flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
return;
}
@@ -228,7 +227,7 @@ void FactsGenerator::VisitCXXConstructExpr(const
CXXConstructExpr *CCE) {
if (const auto *RD = CCE->getType()->getAsCXXRecordDecl();
RD && isStdCallableWrapperType(RD) && CCE->getNumArgs() == 1) {
const Expr *Arg = CCE->getArg(0);
- if (OriginList *ArgList = getRValueOrigins(Arg, getOriginsList(*Arg))) {
+ if (OriginList *ArgList = readValue(Arg)) {
flow(getOriginsList(*CCE), ArgList, /*Kill=*/true);
return;
}
@@ -288,10 +287,17 @@ void FactsGenerator::VisitCXXNullPtrLiteralExpr(
}
void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
+ const Expr *SubExpr = CE->getSubExpr();
+ const CastKind Kind = CE->getCastKind();
+ const bool Loads =
+ Kind == CK_LValueToRValue || Kind == CK_LValueToRValueBitCast;
+ OriginList *Loaded = Loads ? readValue(SubExpr) : nullptr;
+ if (Kind == CK_Dynamic)
+ handleAccess(SubExpr);
+
OriginList *Dest = getOriginsList(*CE);
if (!Dest)
return;
- const Expr *SubExpr = CE->getSubExpr();
OriginList *Src = getOriginsList(*SubExpr);
switch (CE->getCastKind()) {
@@ -302,10 +308,8 @@ void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
assert(Src && "LValue being cast to RValue has no origin list");
// The result of an LValue-to-RValue cast on a pointer lvalue (like `q` in
// `int *p, *q; p = q;`) should propagate the inner origin (what the
pointer
- // points to), not the outer origin (the pointer's storage location). Strip
- // the outer lvalue origin.
- flow(getOriginsList(*CE), getRValueOrigins(SubExpr, Src),
- /*Kill=*/true);
+ // points to), not the outer origin (the pointer's storage location).
+ flow(Dest, Loaded, /*Kill=*/true);
return;
case CK_NullToPointer:
getOriginsList(*CE);
@@ -351,7 +355,7 @@ void FactsGenerator::VisitCastExpr(const CastExpr *CE) {
// lvalue level first. A bit-cast that materializes a pointer from a
// non-pointer representation has no matching source origin and is
// untracked.
- OriginList *RVSrc = getRValueOrigins(SubExpr, Src);
+ OriginList *RVSrc = Loads ? Loaded : Src;
if (RVSrc && Dest->getLength() == RVSrc->getLength())
flow(Dest, RVSrc, /*Kill=*/true);
return;
@@ -393,18 +397,17 @@ void FactsGenerator::VisitUnaryOperator(const
UnaryOperator *UO) {
if (!UO->getType()->isPointerType())
return;
const Expr *SubExpr = UO->getSubExpr();
- flow(getOriginsList(*UO),
- getRValueOrigins(SubExpr, getOriginsList(*SubExpr)), /*Kill=*/true);
+ flow(getOriginsList(*UO), readValue(SubExpr), /*Kill=*/true);
return;
}
case UO_PreInc:
case UO_PostInc:
case UO_PreDec:
case UO_PostDec: {
+ handleAccess(UO->getSubExpr());
// Inc/dec keeps a pointer in the same allocation, so the result carries
the
// operand's loans. Peel the operand's storage origin when the *result* is
a
- // prvalue (post-inc/dec, or any form in C) -- the inverse of
- // getRValueOrigins, which peels when its own argument is a glvalue.
+ // prvalue (post-inc/dec, or any form in C).
if (!UO->getType()->isPointerType())
return;
OriginList *SubList = getOriginsList(*UO->getSubExpr());
@@ -430,6 +433,8 @@ void FactsGenerator::handleAssignment(const Expr
*TargetExpr,
const Expr *LHSExpr,
const Expr *RHSExpr) {
LHSExpr = LHSExpr->IgnoreParenImpCasts();
+ handleAccess(LHSExpr);
+ OriginList *RHSList = readValue(RHSExpr);
OriginList *LHSList = nullptr;
if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
@@ -445,37 +450,7 @@ void FactsGenerator::handleAssignment(const Expr
*TargetExpr,
}
if (!LHSList)
return;
- OriginList *RHSList = getOriginsList(*RHSExpr);
- // For operator= with reference parameters (e.g.,
- // `View& operator=(const View&)`), the RHS argument stays an lvalue,
- // unlike built-in assignment where LValueToRValue cast strips the outer
- // lvalue origin. Strip it manually to get the actual value origins being
- // assigned.
- RHSList = getRValueOrigins(RHSExpr, RHSList);
- if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr)) {
- QualType QT = DRE_LHS->getDecl()->getType();
- if (QT->isReferenceType()) {
- if (hasOrigins(QT->getPointeeType())) {
- // Writing through a reference uses the binding but overwrites the
- // pointee. Model this as a Read of the outer origin (keeping the
- // binding live) and a Write of the inner origins (killing the
pointee's
- // liveness).
- if (UseFact *UF = UseFacts.lookup(DRE_LHS)) {
- const OriginList *FullList = UF->getUsedOrigins();
- assert(FullList);
- UF->setUsedOrigins(FactMgr.getOriginMgr().createSingleOriginList(
- FullList->getOuterOriginID()));
- if (const OriginList *InnerList = FullList->peelOuterOrigin()) {
- UseFact *WriteUF = FactMgr.createFact<UseFact>(DRE_LHS, InnerList);
- WriteUF->markAsWritten();
- CurrentBlockFacts.push_back(WriteUF);
- }
- }
- }
- } else
- markUseAsWrite(DRE_LHS);
- }
if (!RHSList) {
// RHS has no tracked origins (e.g., assigning a callable without origins
// to std::function). Clear loans of the destination.
@@ -492,7 +467,7 @@ void FactsGenerator::handleAssignment(const Expr
*TargetExpr,
// In C, assignment expressions are not GLValues, so the assignment result
has
// the assigned value origins, not the LHS storage origin.
if (IsCMode)
- LHSList = getRValueOrigins(LHSExpr, LHSList);
+ LHSList = LHSList->peelOuterOrigin();
flow(getOriginsList(*TargetExpr), LHSList, /*Kill=*/true);
}
@@ -519,14 +494,12 @@ void FactsGenerator::VisitBinaryOperator(const
BinaryOperator *BO) {
// counterpart in the object's origin -- so the lists may differ in length
// and we flow just the top level, leaving the member's value untouched.
OriginList *Dst = getOriginsList(*BO);
- OriginList *ObjSrc =
- BO->getOpcode() == BO_PtrMemD
- ? getOriginsList(*BO->getLHS())
- : getRValueOrigins(BO->getLHS(), getOriginsList(*BO->getLHS()));
+ OriginList *ObjSrc = BO->getOpcode() == BO_PtrMemD
+ ? getOriginsList(*BO->getLHS())
+ : readValue(BO->getLHS());
if (Dst && ObjSrc)
CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
Dst->getOuterOriginID(), ObjSrc->getOuterOriginID(), /*Kill=*/true));
- handleUse(BO->getLHS());
return;
}
if (BO->getOpcode() == BO_Comma) {
@@ -534,6 +507,7 @@ void FactsGenerator::VisitBinaryOperator(const
BinaryOperator *BO) {
return;
}
if (BO->isCompoundAssignmentOp()) {
+ handleAccess(BO->getLHS());
// A pointer compound additive assignment (`p += n`) carries the LHS's
loans
// like inc/dec above; in C the result is a prvalue, so peel its outer
// (storage) origin.
@@ -546,10 +520,9 @@ void FactsGenerator::VisitBinaryOperator(const
BinaryOperator *BO) {
}
if (BO->getType()->isPointerType() && BO->isAdditiveOp())
handlePointerArithmetic(BO);
- handleUse(BO->getRHS());
if (BO->isAssignmentOp())
handleAssignment(BO, BO->getLHS(), BO->getRHS());
- // TODO: Handle assignments involving dereference like `*p = q`.
+ // TODO: Propagate origins for assignments through a dereference (`*p = q`).
}
static const CFGBlock *findPredBlockForExpr(const CFGBlock *MergeBlock,
@@ -666,7 +639,7 @@ void FactsGenerator::VisitMaterializeTemporaryExpr(
MTEList->getLength() == (SubExprList->getLength() + 1)) &&
"MTE top level origin should contain a loan to the MTE itself");
- OriginList *RValMTEList = getRValueOrigins(MTE, MTEList);
+ OriginList *RValMTEList = MTEList->peelOuterOrigin();
flow(RValMTEList, SubExprList, /*Kill=*/true);
OriginID OuterMTEID = MTEList->getOuterOriginID();
if (MTE->getStorageDuration() == SD_FullExpression) {
@@ -702,6 +675,8 @@ void FactsGenerator::VisitLambdaExpr(const LambdaExpr *LE) {
for (const Expr *Init : LE->capture_inits()) {
if (!Init)
continue;
+ // The lambda body may dereference a capture to any depth.
+ handleUse(Init);
OriginList *InitList = getOriginsList(*Init);
if (!InitList)
continue;
@@ -758,6 +733,8 @@ bool FactsGenerator::handlePlacementNew(const CXXNewExpr
*NE,
// FIXME: General placement arguments need separate handling to overwrite
// the right origins.
+ handleAccess(PlacementArg);
+
// The pointer returned by placement new comes from the placement
// argument.
if (PlacementList)
@@ -796,7 +773,30 @@ void FactsGenerator::VisitCXXNewExpr(const CXXNewExpr *NE)
{
flow(NewList, InitList, true);
}
+// TODO: An escape fact may fit `throw` and asm better than a use.
+void FactsGenerator::VisitCXXThrowExpr(const CXXThrowExpr *TE) {
+ if (const Expr *Sub = TE->getSubExpr())
+ handleUse(Sub);
+}
+
+void FactsGenerator::VisitGCCAsmStmt(const GCCAsmStmt *AS) {
+ for (const Expr *Input : AS->inputs())
+ handleUse(Input);
+ for (unsigned I = 0, N = AS->getNumOutputs(); I != N; ++I)
+ if (AS->isOutputPlusConstraint(I)) // Also read.
+ handleUse(AS->getOutputExpr(I));
+ else
+ handleAccess(AS->getOutputExpr(I));
+}
+
+void FactsGenerator::VisitCXXTypeidExpr(const CXXTypeidExpr *TE) {
+ if (TE->isPotentiallyEvaluated())
+ handleAccess(TE->getExprOperand());
+}
+
void FactsGenerator::VisitCXXDeleteExpr(const CXXDeleteExpr *DE) {
+ // The destructor may dereference to any depth.
+ handleUse(DE->getArgument());
OriginList *List = getOriginsList(*DE->getArgument());
CurrentBlockFacts.push_back(
FactMgr.createFact<InvalidateOriginFact>(List->getOuterOriginID(), DE));
@@ -813,7 +813,7 @@ void FactsGenerator::VisitStmtExpr(const StmtExpr *SE) {
if (!Last)
return;
if (OriginList *Dst = getOriginsList(*SE))
- if (OriginList *Src = getRValueOrigins(Last, getOriginsList(*Last)))
+ if (OriginList *Src = readValue(Last))
flow(Dst, Src, /*Kill=*/true);
}
@@ -877,13 +877,12 @@ void FactsGenerator::handleGSLPointerConstruction(const
CXXConstructExpr *CCE) {
const Expr *Arg = CCE->getArg(0);
if (isGslPointerType(Arg->getType())) {
- OriginList *ArgList = getOriginsList(*Arg);
- assert(ArgList && "GSL pointer argument should have an origin list");
// GSL pointer is constructed from another gsl pointer.
// Example:
// View(View v);
// View(const View &v);
- ArgList = getRValueOrigins(Arg, ArgList);
+ OriginList *ArgList = readValue(Arg);
+ assert(ArgList && "GSL pointer argument should have an...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/225799
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits