[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
Fangyi Zhou via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 24 14:31:53 PST 2025
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/128251
>From 9ab9088bced8acc6f362240b531647f9e5854398 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Fri, 21 Feb 2025 20:54:08 +0000
Subject: [PATCH 01/26] WIP: use CFGElement in conjuredSymbol
---
.../Core/PathSensitive/SValBuilder.h | 87 +++++++++--------
.../Core/PathSensitive/SymbolManager.h | 56 +++++++----
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 18 ++--
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 55 ++++++-----
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 13 +--
.../Core/ExprEngineCallAndReturn.cpp | 6 +-
.../StaticAnalyzer/Core/ExprEngineObjC.cpp | 16 ++--
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 93 +++++++++++--------
8 files changed, 200 insertions(+), 144 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 54430d426a82a..5b2887b0f9a86 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Type.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
@@ -171,20 +172,27 @@ class SValBuilder {
// Forwarding methods to SymbolManager.
- const SymbolConjured* conjureSymbol(const Stmt *stmt,
+ const SymbolConjured *conjureSymbol(const CFGBlock::CFGElementRef ElemRef,
const LocationContext *LCtx,
- QualType type,
- unsigned visitCount,
+ QualType type, unsigned visitCount,
const void *symbolTag = nullptr) {
- return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
+ return SymMgr.conjureSymbol(ElemRef, LCtx, type, visitCount, symbolTag);
}
- const SymbolConjured* conjureSymbol(const Expr *expr,
- const LocationContext *LCtx,
- unsigned visitCount,
- const void *symbolTag = nullptr) {
- return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
- }
+ // const SymbolConjured* conjureSymbol(const Stmt *stmt,
+ // const LocationContext *LCtx,
+ // QualType type,
+ // unsigned visitCount,
+ // const void *symbolTag = nullptr) {
+ // return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
+ // }
+
+ // const SymbolConjured* conjureSymbol(const Expr *expr,
+ // const LocationContext *LCtx,
+ // unsigned visitCount,
+ // const void *symbolTag = nullptr) {
+ // return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
+ // }
/// Construct an SVal representing '0' for the specified type.
DefinedOrUnknownSVal makeZeroVal(QualType type);
@@ -198,33 +206,38 @@ class SValBuilder {
/// The advantage of symbols derived/built from other symbols is that we
/// preserve the relation between related(or even equivalent) expressions, so
/// conjured symbols should be used sparingly.
- DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag,
- const Expr *expr,
- const LocationContext *LCtx,
- unsigned count);
- DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Stmt *S,
- const LocationContext *LCtx,
- QualType type, unsigned count);
- DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount);
-
- /// Conjure a symbol representing heap allocated memory region.
- ///
- /// Note, the expression should represent a location.
- DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
- const LocationContext *LCtx,
- unsigned Count);
-
- /// Conjure a symbol representing heap allocated memory region.
- ///
- /// Note, now, the expression *doesn't* need to represent a location.
- /// But the type need to!
- DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
- const LocationContext *LCtx,
- QualType type, unsigned Count);
-
+ // DefinedOrUnknownSVal
+ // conjureSymbolVal(const void *symbolTag,
+ // const CFGBlock::ConstCFGElementRef elemRef,
+ // const LocationContext *LCtx, unsigned count);
+ DefinedOrUnknownSVal
+ conjureSymbolVal(const void *symbolTag,
+ const CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *LCtx, QualType type, unsigned count);
+ DefinedOrUnknownSVal
+ conjureSymbolVal(const CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *LCtx, QualType type,
+ unsigned visitCount);
+
+ // /// Conjure a symbol representing heap allocated memory region.
+ // ///
+ // /// Note, the expression should represent a location.
+ // DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
+ // const LocationContext *LCtx,
+ // unsigned Count);
+
+ // /// Conjure a symbol representing heap allocated memory region.
+ // ///
+ // /// Note, now, the expression *doesn't* need to represent a location.
+ // /// But the type need to!
+ // DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
+ // const LocationContext *LCtx,
+ // QualType type, unsigned Count);
+
+ DefinedSVal
+ getConjuredHeapSymbolVal(const CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *LCtx, QualType type,
+ unsigned Count);
/// Create an SVal representing the result of an alloca()-like call, that is,
/// an AllocaRegion on the stack.
///
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index cbbea1b56bb40..10b2b91036f2f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -17,6 +17,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -85,12 +86,14 @@ class SymbolConjured : public SymbolData {
unsigned Count;
const LocationContext *LCtx;
const void *SymbolTag;
+ const CFGBlock::ConstCFGElementRef ElemRef;
friend class SymExprAllocator;
- SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
- QualType t, unsigned count, const void *symbolTag)
- : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
- LCtx(lctx), SymbolTag(symbolTag) {
+ SymbolConjured(SymbolID sym, CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *lctx, QualType t, unsigned count,
+ const void *symbolTag)
+ : SymbolData(SymbolConjuredKind, sym), S(nullptr), T(t), Count(count),
+ LCtx(lctx), SymbolTag(symbolTag), ElemRef(elemRef) {
// FIXME: 's' might be a nullptr if we're conducting invalidation
// that was caused by a destructor call on a temporary object,
// which has no statement associated with it.
@@ -102,7 +105,12 @@ class SymbolConjured : public SymbolData {
public:
/// It might return null.
- const Stmt *getStmt() const { return S; }
+ const Stmt *getStmt() const {
+ if (auto Stmt = ElemRef->getAs<CFGStmt>()) {
+ return Stmt->getStmt();
+ }
+ return S;
+ }
unsigned getCount() const { return Count; }
/// It might return null.
const void *getTag() const { return SymbolTag; }
@@ -113,11 +121,13 @@ class SymbolConjured : public SymbolData {
void dumpToStream(raw_ostream &os) const override;
- static void Profile(llvm::FoldingSetNodeID &profile, const Stmt *S,
+ static void Profile(llvm::FoldingSetNodeID &profile,
+ const CFGBlock::ConstCFGElementRef ElemRef,
const LocationContext *LCtx, QualType T, unsigned Count,
const void *SymbolTag) {
profile.AddInteger((unsigned)SymbolConjuredKind);
- profile.AddPointer(S);
+ // profile.Add(ElemRef);
+ // profile.AddPointer(S);
profile.AddPointer(LCtx);
profile.Add(T);
profile.AddInteger(Count);
@@ -125,7 +135,7 @@ class SymbolConjured : public SymbolData {
}
void Profile(llvm::FoldingSetNodeID& profile) override {
- Profile(profile, S, LCtx, T, Count, SymbolTag);
+ Profile(profile, ElemRef, LCtx, T, Count, SymbolTag);
}
// Implement isa<T> support.
@@ -533,20 +543,28 @@ class SymbolManager {
template <typename SymExprT, typename... Args>
const SymExprT *acquire(Args &&...args);
- const SymbolConjured *conjureSymbol(const Stmt *E,
- const LocationContext *LCtx, QualType T,
- unsigned VisitCount,
- const void *SymbolTag = nullptr) {
- return acquire<SymbolConjured>(E, LCtx, T, VisitCount, SymbolTag);
- }
+ // const SymbolConjured *conjureSymbol(const Stmt *E,
+ // const LocationContext *LCtx, QualType
+ // T, unsigned VisitCount, const void
+ // *SymbolTag = nullptr) {
+ // return acquire<SymbolConjured>(E, LCtx, T, VisitCount, SymbolTag);
+ // }
- const SymbolConjured* conjureSymbol(const Expr *E,
- const LocationContext *LCtx,
- unsigned VisitCount,
- const void *SymbolTag = nullptr) {
- return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag);
+ const SymbolConjured *
+ conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef,
+ const LocationContext *LCtx, QualType T, unsigned VisitCount,
+ const void *SymbolTag = nullptr) {
+
+ return acquire<SymbolConjured>(ElemRef, LCtx, T, VisitCount, SymbolTag);
}
+ // const SymbolConjured* conjureSymbol(const Expr *E,
+ // const LocationContext *LCtx,
+ // unsigned VisitCount,
+ // const void *SymbolTag = nullptr) {
+ // return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag);
+ // }
+
QualType getType(const SymExpr *SE) const {
return SE->getType();
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 318fa3c1caf06..6c569e4ccadbe 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -437,8 +437,8 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
// values inside Reg would be correct.
SVal InitVal = State->getSVal(Init, LC);
if (InitVal.isUnknown()) {
- InitVal = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(),
- currBldrCtx->blockCount());
+ InitVal = getSValBuilder().conjureSymbolVal(
+ getCFGElementRef(), LC, Init->getType(), currBldrCtx->blockCount());
State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false);
// Then we'd need to take the value that certainly exists and bind it
@@ -447,7 +447,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
// Try to recover some path sensitivity in case we couldn't
// compute the value.
InitValWithAdjustments = getSValBuilder().conjureSymbolVal(
- Result, LC, InitWithAdjustments->getType(),
+ getCFGElementRef(), LC, InitWithAdjustments->getType(),
currBldrCtx->blockCount());
}
State =
@@ -1213,9 +1213,9 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
// If we fail to get the value for some reason, use a symbolic value.
if (InitVal.isUnknownOrUndef()) {
SValBuilder &SVB = getSValBuilder();
- InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame,
- Field->getType(),
- currBldrCtx->blockCount());
+ InitVal =
+ SVB.conjureSymbolVal(getCFGElementRef(), stackFrame,
+ Field->getType(), currBldrCtx->blockCount());
}
} else {
InitVal = State->getSVal(BMI->getInit(), stackFrame);
@@ -2042,9 +2042,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
for (const auto N : preVisit) {
const LocationContext *LCtx = N->getLocationContext();
- SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
- resultType,
- currBldrCtx->blockCount());
+ SVal result =
+ svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
+ resultType, currBldrCtx->blockCount());
ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result);
// Escape pointers passed into the list, unless it's an ObjC boxed
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 1061dafbb2473..169983605f5f0 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include <optional>
@@ -26,13 +27,15 @@ using llvm::APSInt;
/// (offset) if it is unknown so that memory arithmetic always
/// results in an ElementRegion.
/// \p Count The number of times the current basic block was visited.
-static SVal conjureOffsetSymbolOnLocation(
- SVal Symbol, SVal Other, Expr* Expression, SValBuilder &svalBuilder,
- unsigned Count, const LocationContext *LCtx) {
- QualType Ty = Expression->getType();
+static SVal conjureOffsetSymbolOnLocation(SVal Symbol, SVal Other,
+ CFGBlock::ConstCFGElementRef elemRef,
+ QualType Ty, SValBuilder &svalBuilder,
+ unsigned Count,
+ const LocationContext *LCtx) {
+ // QualType Ty = Expression->getType();
if (isa<Loc>(Other) && Ty->isIntegralOrEnumerationType() &&
Symbol.isUnknown()) {
- return svalBuilder.conjureSymbolVal(Expression, LCtx, Ty, Count);
+ return svalBuilder.conjureSymbolVal(elemRef, LCtx, Ty, Count);
}
return Symbol;
}
@@ -65,8 +68,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// FIXME: Handle structs.
if (RightV.isUnknown()) {
unsigned Count = currBldrCtx->blockCount();
- RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx,
- Count);
+ RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
+ B->getRHS()->getType(), Count);
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
@@ -84,9 +87,11 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// SymSymExpr.
unsigned Count = currBldrCtx->blockCount();
RightV = conjureOffsetSymbolOnLocation(
- RightV, LeftV, RHS, svalBuilder, Count, LCtx);
- LeftV = conjureOffsetSymbolOnLocation(
- LeftV, RightV, LHS, svalBuilder, Count, LCtx);
+ RightV, LeftV, getCFGElementRef(), RHS->getType(), svalBuilder,
+ Count, LCtx);
+ LeftV = conjureOffsetSymbolOnLocation(LeftV, RightV, getCFGElementRef(),
+ LHS->getType(), svalBuilder,
+ Count, LCtx);
}
// Although we don't yet model pointers-to-members, we do need to make
@@ -165,8 +170,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the
// LValue on the LHS will bind to.
- LHSVal = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(), LCtx, LTy,
- currBldrCtx->blockCount());
+ LHSVal = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
+ LTy, currBldrCtx->blockCount());
// However, we need to convert the symbol to the computation type.
Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
} else {
@@ -459,9 +464,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
} else {
// If we don't know if the cast succeeded, conjure a new symbol.
if (val.isUnknown()) {
- DefinedOrUnknownSVal NewSym =
- svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType,
- currBldrCtx->blockCount());
+ DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(
+ nullptr, getCFGElementRef(), LCtx, resultType,
+ currBldrCtx->blockCount());
state = state->BindExpr(CastE, LCtx, NewSym);
} else
// Else, bind to the derived region value.
@@ -483,9 +488,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// Failed to cast or the result is unknown, fall back to conservative.
if (val.isUnknown()) {
- val =
- svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType,
- currBldrCtx->blockCount());
+ val = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
+ resultType,
+ currBldrCtx->blockCount());
}
state = state->BindExpr(CastE, LCtx, val);
Bldr.generateNode(CastE, Pred, state);
@@ -529,7 +534,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (CastE->isGLValue())
resultType = getContext().getPointerType(resultType);
SVal result = svalBuilder.conjureSymbolVal(
- /*symbolTag=*/nullptr, CastE, LCtx, resultType,
+ /*symbolTag=*/nullptr, getCFGElementRef(), LCtx, resultType,
currBldrCtx->blockCount());
state = state->BindExpr(CastE, LCtx, result);
Bldr.generateNode(CastE, Pred, state);
@@ -621,8 +626,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
Ty = getContext().getPointerType(Ty);
}
- InitVal = svalBuilder.conjureSymbolVal(nullptr, InitEx, LC, Ty,
- currBldrCtx->blockCount());
+ InitVal = svalBuilder.conjureSymbolVal(
+ nullptr, getCFGElementRef(), LC, Ty, currBldrCtx->blockCount());
}
@@ -839,8 +844,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
}
if (!hasValue)
- V = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
- currBldrCtx->blockCount());
+ V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
+ Ex->getType(), currBldrCtx->blockCount());
// Generate a new node with the binding from the appropriate path.
B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true));
@@ -1122,8 +1127,8 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal =
- svalBuilder.conjureSymbolVal(nullptr, U, LCtx,
- currBldrCtx->blockCount());
+ svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
+ U->getType(), currBldrCtx->blockCount());
Result = SymVal;
// If the value is a location, ++/-- should always preserve
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index f7020da2e6da2..0860402778826 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -235,8 +235,8 @@ SVal ExprEngine::computeObjectUnderConstruction(
assert(RetE && "Void returns should not have a construction context");
QualType ReturnTy = RetE->getType();
QualType RegionTy = ACtx.getPointerType(ReturnTy);
- return SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy,
- currBldrCtx->blockCount());
+ return SVB.conjureSymbolVal(&TopLevelSymRegionTag, getCFGElementRef(),
+ SFC, RegionTy, currBldrCtx->blockCount());
}
llvm_unreachable("Unhandled return value construction context!");
}
@@ -967,10 +967,11 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// a custom global allocator.
if (symVal.isUnknown()) {
if (IsStandardGlobalOpNewFunction)
- symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
+ symVal = svalBuilder.getConjuredHeapSymbolVal(getCFGElementRef(), LCtx,
+ CNE->getType(), blockCount);
else
- symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(),
- blockCount);
+ symVal = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
+ CNE->getType(), blockCount);
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
@@ -1102,7 +1103,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
}
const LocationContext *LCtx = Pred->getLocationContext();
- SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(),
+ SVal V = svalBuilder.conjureSymbolVal(getCFGElementRef(), LCtx, VD->getType(),
currBldrCtx->blockCount());
ProgramStateRef state = Pred->getState();
state = state->bindLoc(state->getLValue(VD, LCtx), V, LCtx);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 02facf786830d..7207e7950a5bf 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -800,7 +800,8 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// a regular unknown pointer.
const auto *CNE = dyn_cast<CXXNewExpr>(E);
if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
- R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count);
+ R = svalBuilder.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
+ E->getType(), Count);
const MemRegion *MR = R.getAsRegion()->StripCasts();
// Store the extent of the allocated object(s).
@@ -824,7 +825,8 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
State = setDynamicExtent(State, MR, Size.castAs<DefinedOrUnknownSVal>());
} else {
- R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);
+ R = svalBuilder.conjureSymbolVal(getCFGElementRef(), LCtx, ResultTy,
+ Count);
}
}
return State->BindExpr(E, LCtx, R);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 9426e0afd65a0..ac67b9e1dc301 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -45,8 +45,8 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
/// for-loop iterator.
static void populateObjCForDestinationSet(
ExplodedNodeSet &dstLocation, SValBuilder &svalBuilder,
- const ObjCForCollectionStmt *S, const Stmt *elem, SVal elementV,
- SymbolManager &SymMgr, const NodeBuilderContext *currBldrCtx,
+ const ObjCForCollectionStmt *S, const CFGBlock::ConstCFGElementRef elemRef,
+ SVal elementV, SymbolManager &SymMgr, const NodeBuilderContext *currBldrCtx,
StmtNodeBuilder &Bldr, bool hasElements) {
for (ExplodedNode *Pred : dstLocation) {
@@ -66,8 +66,8 @@ static void populateObjCForDestinationSet(
SVal V;
if (hasElements) {
- SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T,
- currBldrCtx->blockCount());
+ SymbolRef Sym =
+ SymMgr.conjureSymbol(elemRef, LCtx, T, currBldrCtx->blockCount());
V = svalBuilder.makeLoc(Sym);
} else {
V = svalBuilder.makeIntVal(0, T);
@@ -110,6 +110,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
const Stmt *elem = S->getElement();
const Stmt *collection = S->getCollection();
+ const CFGBlock::ConstCFGElementRef elemRef = getCFGElementRef();
ProgramStateRef state = Pred->getState();
SVal collectionV = state->getSVal(collection, Pred->getLocationContext());
@@ -132,11 +133,12 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
StmtNodeBuilder Bldr(dstLocation, Tmp, *currBldrCtx);
if (!isContainerNull)
- populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem,
- elementV, SymMgr, currBldrCtx, Bldr,
+ populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S,
+ elemRef, elementV, SymMgr, currBldrCtx,
+ Bldr,
/*hasElements=*/true);
- populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elem,
+ populateObjCForDestinationSet(DstLocationSingleton, svalBuilder, S, elemRef,
elementV, SymMgr, currBldrCtx, Bldr,
/*hasElements=*/false);
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 4f45b24be86c1..dd173a35cfd73 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -151,36 +151,35 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) {
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag,
- const Expr *Ex,
- const LocationContext *LCtx,
- unsigned Count) {
- QualType T = Ex->getType();
-
- if (T->isNullPtrType())
- return makeZeroVal(T);
-
- // Compute the type of the result. If the expression is not an R-value, the
- // result should be a location.
- QualType ExType = Ex->getType();
- if (Ex->isGLValue())
- T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType);
-
- return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count);
-}
+// DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag,
+// const Expr *Ex,
+// const LocationContext
+// *LCtx, unsigned Count) {
+// QualType T = Ex->getType();
+//
+// if (T->isNullPtrType())
+// return makeZeroVal(T);
+//
+// // Compute the type of the result. If the expression is not an R-value, the
+// // result should be a location.
+// QualType ExType = Ex->getType();
+// if (Ex->isGLValue())
+// T =
+// LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType);
+//
+// return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count);
+// }
-DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
- const Stmt *St,
- const LocationContext *LCtx,
- QualType type,
- unsigned count) {
+DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(
+ const void *symbolTag, const CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *LCtx, QualType type, unsigned count) {
if (type->isNullPtrType())
return makeZeroVal(type);
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.conjureSymbol(St, LCtx, type, count, symbolTag);
+ SymbolRef sym = SymMgr.conjureSymbol(elemRef, LCtx, type, count, symbolTag);
if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -188,17 +187,17 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag,
return nonloc::SymbolVal(sym);
}
-DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
- const LocationContext *LCtx,
- QualType type,
- unsigned visitCount) {
+DefinedOrUnknownSVal
+SValBuilder::conjureSymbolVal(const CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *LCtx, QualType type,
+ unsigned visitCount) {
if (type->isNullPtrType())
return makeZeroVal(type);
if (!SymbolManager::canSymbolicate(type))
return UnknownVal();
- SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount);
+ SymbolRef sym = SymMgr.conjureSymbol(elemRef, LCtx, type, visitCount);
if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
@@ -206,17 +205,33 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
return nonloc::SymbolVal(sym);
}
-DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
- const LocationContext *LCtx,
- unsigned VisitCount) {
- QualType T = E->getType();
- return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
-}
+// DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
+// const LocationContext
+// *LCtx, unsigned VisitCount)
+// {
+// QualType T = E->getType();
+// return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
+// }
+//
+// DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
+// const LocationContext
+// *LCtx, QualType type,
+// unsigned VisitCount) {
+// assert(Loc::isLocType(type));
+// assert(SymbolManager::canSymbolicate(type));
+// if (type->isNullPtrType()) {
+// // makeZeroVal() returns UnknownVal only in case of FP number, which
+// // is not the case.
+// return makeZeroVal(type).castAs<DefinedSVal>();
+// }
+//
+// SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount);
+// return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
+// }
-DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
- const LocationContext *LCtx,
- QualType type,
- unsigned VisitCount) {
+DefinedSVal SValBuilder::getConjuredHeapSymbolVal(
+ const CFGBlock::ConstCFGElementRef elemRef, const LocationContext *LCtx,
+ QualType type, unsigned VisitCount) {
assert(Loc::isLocType(type));
assert(SymbolManager::canSymbolicate(type));
if (type->isNullPtrType()) {
@@ -225,7 +240,7 @@ DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
return makeZeroVal(type).castAs<DefinedSVal>();
}
- SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount);
+ SymbolRef sym = SymMgr.conjureSymbol(elemRef, LCtx, type, VisitCount);
return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
}
>From 6b6d6da6b8b290090d7fa845f69fba400f131dcc Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Fri, 21 Feb 2025 21:36:29 +0000
Subject: [PATCH 02/26] Convert more references
---
.../Core/PathSensitive/CheckerContext.h | 5 ++
.../Checkers/ContainerModeling.cpp | 33 +++++------
clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 57 ++++++++++---------
3 files changed, 53 insertions(+), 42 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 168983fd5cb68..02bd4a91961a9 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -151,6 +151,11 @@ class CheckerContext {
return Pred->getSVal(S);
}
+ /// Get the CFG Element Ref from the ExprEngine
+ CFGBlock::ConstCFGElementRef getCFGElementRef() const {
+ return Eng.getCFGElementRef();
+ }
+
/// Returns true if the value of \p E is greater than or equal to \p
/// Val under unsigned comparison
bool isGreaterOrEqual(const Expr *E, unsigned long long Val);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
index 55ed809bfed6c..74a7b8e0f54ff 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -107,13 +107,13 @@ bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
-ProgramStateRef createContainerBegin(ProgramStateRef State,
+ProgramStateRef createContainerBegin(CheckerContext &C, ProgramStateRef State,
const MemRegion *Cont, const Expr *E,
QualType T, const LocationContext *LCtx,
unsigned BlockCount);
-ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
- const Expr *E, QualType T,
- const LocationContext *LCtx,
+ProgramStateRef createContainerEnd(CheckerContext &C, ProgramStateRef State,
+ const MemRegion *Cont, const Expr *E,
+ QualType T, const LocationContext *LCtx,
unsigned BlockCount);
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
const ContainerData &CData);
@@ -260,8 +260,9 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
auto State = C.getState();
auto BeginSym = getContainerBegin(State, ContReg);
if (!BeginSym) {
- State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
- C.getLocationContext(), C.blockCount());
+ State =
+ createContainerBegin(C, State, ContReg, CE, C.getASTContext().LongTy,
+ C.getLocationContext(), C.blockCount());
BeginSym = getContainerBegin(State, ContReg);
}
State = setIteratorPosition(State, RetVal,
@@ -282,7 +283,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
auto State = C.getState();
auto EndSym = getContainerEnd(State, ContReg);
if (!EndSym) {
- State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
+ State = createContainerEnd(C, State, ContReg, CE, C.getASTContext().LongTy,
C.getLocationContext(), C.blockCount());
EndSym = getContainerEnd(State, ContReg);
}
@@ -326,7 +327,7 @@ void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
auto &SVB = C.getSValBuilder();
// Then generate and assign a new "end" symbol for the new container.
auto NewEndSym =
- SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ SymMgr.conjureSymbol(C.getCFGElementRef(), C.getLocationContext(),
C.getASTContext().LongTy, C.blockCount());
State = assumeNoOverflow(State, NewEndSym, 4);
if (CData) {
@@ -844,7 +845,7 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
return CDataPtr->getEnd();
}
-ProgramStateRef createContainerBegin(ProgramStateRef State,
+ProgramStateRef createContainerBegin(CheckerContext &C, ProgramStateRef State,
const MemRegion *Cont, const Expr *E,
QualType T, const LocationContext *LCtx,
unsigned BlockCount) {
@@ -854,8 +855,8 @@ ProgramStateRef createContainerBegin(ProgramStateRef State,
return State;
auto &SymMgr = State->getSymbolManager();
- const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
- "begin");
+ const SymbolConjured *Sym =
+ SymMgr.conjureSymbol(C.getCFGElementRef(), LCtx, T, BlockCount, "begin");
State = assumeNoOverflow(State, Sym, 4);
if (CDataPtr) {
@@ -867,9 +868,9 @@ ProgramStateRef createContainerBegin(ProgramStateRef State,
return setContainerData(State, Cont, CData);
}
-ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
- const Expr *E, QualType T,
- const LocationContext *LCtx,
+ProgramStateRef createContainerEnd(CheckerContext &C, ProgramStateRef State,
+ const MemRegion *Cont, const Expr *E,
+ QualType T, const LocationContext *LCtx,
unsigned BlockCount) {
// Only create if it does not exist
const auto *CDataPtr = getContainerData(State, Cont);
@@ -877,8 +878,8 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
return State;
auto &SymMgr = State->getSymbolManager();
- const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
- "end");
+ const SymbolConjured *Sym =
+ SymMgr.conjureSymbol(C.getCFGElementRef(), LCtx, T, BlockCount, "end");
State = assumeNoOverflow(State, Sym, 4);
if (CDataPtr) {
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 5a5a6948098e7..88aae1836d20b 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -19,6 +19,7 @@
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
@@ -473,11 +474,11 @@ class RegionStoreManager : public StoreManager {
//===-------------------------------------------------------------------===//
// Binding values to regions.
//===-------------------------------------------------------------------===//
- RegionBindingsRef invalidateGlobalRegion(MemRegion::Kind K, const Stmt *S,
- unsigned Count,
- const LocationContext *LCtx,
- RegionBindingsRef B,
- InvalidatedRegions *Invalidated);
+ RegionBindingsRef
+ invalidateGlobalRegion(MemRegion::Kind K,
+ const CFGBlock::ConstCFGElementRef elemRef,
+ unsigned Count, const LocationContext *LCtx,
+ RegionBindingsRef B, InvalidatedRegions *Invalidated);
StoreRef invalidateRegions(Store store, ArrayRef<SVal> Values, const Stmt *S,
unsigned Count, const LocationContext *LCtx,
@@ -1044,7 +1045,7 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B,
namespace {
class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker>
{
- const Stmt *S;
+ const CFGBlock::ConstCFGElementRef ElemRef;
unsigned Count;
const LocationContext *LCtx;
InvalidatedSymbols &IS;
@@ -1053,14 +1054,16 @@ class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker>
GlobalsFilterKind GlobalsFilter;
public:
InvalidateRegionsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr,
- RegionBindingsRef b, const Stmt *S, unsigned count,
- const LocationContext *lctx, InvalidatedSymbols &is,
+ RegionBindingsRef b,
+ const CFGBlock::ConstCFGElementRef elemRef,
+ unsigned count, const LocationContext *lctx,
+ InvalidatedSymbols &is,
RegionAndSymbolInvalidationTraits &ITraitsIn,
StoreManager::InvalidatedRegions *r,
GlobalsFilterKind GFK)
- : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b), S(S),
- Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r),
- GlobalsFilter(GFK) {}
+ : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b),
+ ElemRef(elemRef), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn),
+ Regions(r), GlobalsFilter(GFK) {}
void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
void VisitBinding(SVal V);
@@ -1193,7 +1196,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelevant.
DefinedOrUnknownSVal V =
- svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count);
+ svalBuilder.conjureSymbolVal(baseR, ElemRef, LCtx, Ctx.IntTy, Count);
B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -1215,7 +1218,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelevant.
DefinedOrUnknownSVal V =
- svalBuilder.conjureSymbolVal(baseR, S, LCtx, Ctx.IntTy, Count);
+ svalBuilder.conjureSymbolVal(baseR, ElemRef, LCtx, Ctx.IntTy, Count);
B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -1283,13 +1286,13 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
conjure_default:
// Set the default value of the array to conjured symbol.
DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(
- baseR, S, LCtx, AT->getElementType(), Count);
+ baseR, ElemRef, LCtx, AT->getElementType(), Count);
B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
DefinedOrUnknownSVal V =
- svalBuilder.conjureSymbolVal(baseR, S, LCtx, T, Count);
+ svalBuilder.conjureSymbolVal(baseR, ElemRef, LCtx, T, Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
B = B.addBinding(baseR, BindingKey::Direct, V);
}
@@ -1318,15 +1321,15 @@ bool InvalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) {
}
RegionBindingsRef RegionStoreManager::invalidateGlobalRegion(
- MemRegion::Kind K, const Stmt *S, unsigned Count,
- const LocationContext *LCtx, RegionBindingsRef B,
+ MemRegion::Kind K, const CFGBlock::ConstCFGElementRef elemRef,
+ unsigned Count, const LocationContext *LCtx, RegionBindingsRef B,
InvalidatedRegions *Invalidated) {
// Bind the globals memory space to a new symbol that we will use to derive
// the bindings for all globals.
const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K);
- SVal V =
- svalBuilder.conjureSymbolVal(/* symbolTag = */ (const void *)GS, S, LCtx,
- /* type does not matter */ Ctx.IntTy, Count);
+ SVal V = svalBuilder.conjureSymbolVal(
+ /* symbolTag = */ (const void *)GS, elemRef, LCtx,
+ /* type does not matter */ Ctx.IntTy, Count);
B = B.removeBinding(GS)
.addBinding(BindingKey::Make(GS, BindingKey::Default), V);
@@ -1376,8 +1379,8 @@ StoreRef RegionStoreManager::invalidateRegions(
}
RegionBindingsRef B = getRegionBindings(store);
- InvalidateRegionsWorker W(*this, StateMgr, B, S, Count, LCtx, IS, ITraits,
- Invalidated, GlobalsFilter);
+ InvalidateRegionsWorker W(*this, StateMgr, B, Call->getCFGElementRef(), Count,
+ LCtx, IS, ITraits, Invalidated, GlobalsFilter);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
@@ -1396,12 +1399,14 @@ StoreRef RegionStoreManager::invalidateRegions(
// TODO: This could possibly be more precise with modules.
switch (GlobalsFilter) {
case GFK_All:
- B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, S,
- Count, LCtx, B, Invalidated);
+ B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
+ Call->getCFGElementRef(), Count, LCtx, B,
+ Invalidated);
[[fallthrough]];
case GFK_SystemOnly:
- B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, S, Count,
- LCtx, B, Invalidated);
+ B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
+ Call->getCFGElementRef(), Count, LCtx, B,
+ Invalidated);
[[fallthrough]];
case GFK_None:
break;
>From 5f2a57472aec007fcc368e1b1e97685e327bda4b Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Fri, 21 Feb 2025 22:21:21 +0000
Subject: [PATCH 03/26] Convert the checkers
---
.../Core/PathSensitive/SValBuilder.h | 8 ++---
.../Core/PathSensitive/SymbolManager.h | 9 +++--
.../Checkers/CStringChecker.cpp | 34 ++++++++++++-------
.../StaticAnalyzer/Checkers/ErrnoModeling.cpp | 2 +-
.../Checkers/ErrnoTesterChecker.cpp | 3 +-
.../lib/StaticAnalyzer/Checkers/Iterator.cpp | 11 +++---
clang/lib/StaticAnalyzer/Checkers/Iterator.h | 9 ++---
.../Checkers/IteratorModeling.cpp | 29 +++++++++-------
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 6 ++--
.../RetainCountChecker/RetainCountChecker.cpp | 4 +--
.../Checkers/STLAlgorithmModeling.cpp | 13 ++++---
.../Checkers/SmartPtrModeling.cpp | 8 ++---
.../Checkers/StdLibraryFunctionsChecker.cpp | 5 +--
.../StaticAnalyzer/Checkers/StreamChecker.cpp | 3 +-
.../Checkers/cert/InvalidPtrChecker.cpp | 2 +-
.../lib/StaticAnalyzer/Core/SymbolManager.cpp | 2 +-
16 files changed, 85 insertions(+), 63 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 5b2887b0f9a86..6fb5f15822585 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -172,10 +172,10 @@ class SValBuilder {
// Forwarding methods to SymbolManager.
- const SymbolConjured *conjureSymbol(const CFGBlock::CFGElementRef ElemRef,
- const LocationContext *LCtx,
- QualType type, unsigned visitCount,
- const void *symbolTag = nullptr) {
+ const SymbolConjured *
+ conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef,
+ const LocationContext *LCtx, QualType type, unsigned visitCount,
+ const void *symbolTag = nullptr) {
return SymMgr.conjureSymbol(ElemRef, LCtx, type, visitCount, symbolTag);
}
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 10b2b91036f2f..4e24c9a81ae1f 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -81,19 +81,18 @@ class SymbolRegionValue : public SymbolData {
/// A symbol representing the result of an expression in the case when we do
/// not know anything about what the expression is.
class SymbolConjured : public SymbolData {
- const Stmt *S;
+ const CFGBlock::ConstCFGElementRef ElemRef;
QualType T;
unsigned Count;
const LocationContext *LCtx;
const void *SymbolTag;
- const CFGBlock::ConstCFGElementRef ElemRef;
friend class SymExprAllocator;
SymbolConjured(SymbolID sym, CFGBlock::ConstCFGElementRef elemRef,
const LocationContext *lctx, QualType t, unsigned count,
const void *symbolTag)
- : SymbolData(SymbolConjuredKind, sym), S(nullptr), T(t), Count(count),
- LCtx(lctx), SymbolTag(symbolTag), ElemRef(elemRef) {
+ : SymbolData(SymbolConjuredKind, sym), ElemRef(elemRef), T(t),
+ Count(count), LCtx(lctx), SymbolTag(symbolTag) {
// FIXME: 's' might be a nullptr if we're conducting invalidation
// that was caused by a destructor call on a temporary object,
// which has no statement associated with it.
@@ -109,7 +108,7 @@ class SymbolConjured : public SymbolData {
if (auto Stmt = ElemRef->getAs<CFGStmt>()) {
return Stmt->getStmt();
}
- return S;
+ return nullptr;
}
unsigned getCount() const { return Count; }
/// It might return null.
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 39dcaf02dbe25..ea3b815a95bc1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -1515,7 +1515,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
// conjure a return value for later.
if (lastElement.isUnknown())
lastElement = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
+ nullptr, Call.getCFGElementRef(), LCtx,
+ Call.getOriginExpr()->getType(), C.blockCount());
// The byte after the last byte copied is the return value.
state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
@@ -1665,8 +1666,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
if (State) {
// The return value is the comparison result, which we don't know.
- SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
- C.blockCount());
+ SVal CmpV = Builder.conjureSymbolVal(
+ nullptr, Call.getCFGElementRef(), LCtx,
+ Call.getOriginExpr()->getType(), C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
C.addTransition(State);
}
@@ -1770,7 +1772,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
+ nullptr, Call.getCFGElementRef(), LCtx,
+ Call.getOriginExpr()->getType(), C.blockCount());
NonLoc resultNL = result.castAs<NonLoc>();
if (strLengthNL) {
@@ -1794,7 +1797,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
+ nullptr, Call.getCFGElementRef(), LCtx,
+ Call.getOriginExpr()->getType(), C.blockCount());
}
}
@@ -2261,8 +2265,9 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (ReturnEnd && Result.isUnknown()) {
- Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
- C.blockCount());
+ Result = svalBuilder.conjureSymbolVal(
+ nullptr, Call.getCFGElementRef(), LCtx,
+ Call.getOriginExpr()->getType(), C.blockCount());
}
}
// Set the return value.
@@ -2361,8 +2366,9 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
const StringLiteral *RightStrLiteral =
getCStringLiteral(C, state, Right.Expression, RightVal);
bool canComputeResult = false;
- SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
- LCtx, C.blockCount());
+ SVal resultVal = svalBuilder.conjureSymbolVal(
+ nullptr, Call.getCFGElementRef(), LCtx, Call.getOriginExpr()->getType(),
+ C.blockCount());
if (LeftStrLiteral && RightStrLiteral) {
StringRef LeftStrRef = LeftStrLiteral->getString();
@@ -2469,14 +2475,15 @@ void CStringChecker::evalStrsep(CheckerContext &C,
// further along in the same string, or NULL if there are no more tokens.
State =
State->bindLoc(*SearchStrLoc,
- SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(),
+ SVB.conjureSymbolVal(getTag(), Call.getCFGElementRef(),
LCtx, CharPtrTy, C.blockCount()),
LCtx);
} else {
assert(SearchStrVal.isUnknown());
// Conjure a symbolic value. It's the best we can do.
- Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
- C.blockCount());
+ Result =
+ SVB.conjureSymbolVal(nullptr, Call.getCFGElementRef(), LCtx,
+ Call.getOriginExpr()->getType(), C.blockCount());
}
// Set the return value, and finish.
@@ -2520,7 +2527,8 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
SValBuilder &SVB = C.getSValBuilder();
SVal ResultVal =
- SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
+ SVB.conjureSymbolVal(nullptr, Call.getCFGElementRef(), LCtx,
+ Call.getOriginExpr()->getType(), C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
C.addTransition(State);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
index 6ffc05f06742b..cc8f1dd44b7e4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
@@ -124,7 +124,7 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
// of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker
// object.
const SymbolConjured *Sym = SVB.conjureSymbol(
- nullptr, C.getLocationContext(),
+ C.getCFGElementRef(), C.getLocationContext(),
ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
// The symbolic region is untyped, create a typed sub-region in it.
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
index 6076a6bc78973..b47787d59fc62 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
@@ -131,7 +131,8 @@ void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C,
ProgramStateRef StateFailure = State->BindExpr(
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal(
- nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount());
+ nullptr, Call.getCFGElementRef(), C.getLocationContext(),
+ Call.getOriginExpr()->getType(), C.blockCount());
StateFailure = StateFailure->assume(ErrnoVal, true);
assert(StateFailure && "Failed to assume on an initial value.");
StateFailure =
diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
index ba561ddebdb69..31fdf58f6ba1e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "Iterator.h"
+#include "clang/Analysis/CFG.h"
namespace clang {
namespace ento {
@@ -206,15 +207,15 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
return nullptr;
}
-ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
- const MemRegion *Cont, const Stmt *S,
- const LocationContext *LCtx,
- unsigned blockCount) {
+ProgramStateRef
+createIteratorPosition(ProgramStateRef State, SVal Val, const MemRegion *Cont,
+ const CFGBlock::ConstCFGElementRef ElemRef,
+ const LocationContext *LCtx, unsigned blockCount) {
auto &StateMgr = State->getStateManager();
auto &SymMgr = StateMgr.getSymbolManager();
auto &ACtx = StateMgr.getContext();
- auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount);
+ auto Sym = SymMgr.conjureSymbol(ElemRef, LCtx, ACtx.LongTy, blockCount);
State = assumeNoOverflow(State, Sym, 4);
return setIteratorPosition(State, Val,
IteratorPosition::getPosition(Cont, Sym));
diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
index 46de8ea01d77b..dbae7da9cac22 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Iterator.h
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H
+#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
@@ -164,10 +165,10 @@ const ContainerData *getContainerData(ProgramStateRef State,
const IteratorPosition *getIteratorPosition(ProgramStateRef State, SVal Val);
ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
const IteratorPosition &Pos);
-ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
- const MemRegion *Cont, const Stmt *S,
- const LocationContext *LCtx,
- unsigned blockCount);
+ProgramStateRef
+createIteratorPosition(ProgramStateRef State, SVal Val, const MemRegion *Cont,
+ const CFGBlock::ConstCFGElementRef ElemRef,
+ const LocationContext *LCtx, unsigned blockCount);
ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter,
OverloadedOperatorKind Op, SVal Distance);
ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index d4ce73b03acb8..380991f10f499 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -99,7 +99,8 @@ class IteratorModeling
const Expr *OrigExpr,
const AdvanceFn *Handler) const;
- void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
+ void handleComparison(CheckerContext &C, const Expr *CE,
+ const CFGBlock::ConstCFGElementRef ElemRef, SVal RetVal,
SVal LVal, SVal RVal, OverloadedOperatorKind Op) const;
void processComparison(CheckerContext &C, ProgramStateRef State,
SymbolRef Sym1, SymbolRef Sym2, SVal RetVal,
@@ -271,7 +272,7 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
if (isSimpleComparisonOperator(BO->getOpcode())) {
SVal Result = State->getSVal(BO, C.getLocationContext());
- handleComparison(C, BO, Result, LVal, RVal,
+ handleComparison(C, BO, C.getCFGElementRef(), Result, LVal, RVal,
BinaryOperator::getOverloadedOperator(OK));
} else if (isRandomIncrOrDecrOperator(OK)) {
// In case of operator+ the iterator can be either on the LHS (eg.: it + 1),
@@ -355,13 +356,15 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C,
return;
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- handleComparison(C, OrigExpr, Call.getReturnValue(),
- InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
+ handleComparison(C, OrigExpr, Call.getCFGElementRef(),
+ Call.getReturnValue(), InstCall->getCXXThisVal(),
+ Call.getArgSVal(0), Op);
return;
}
- handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
- Call.getArgSVal(1), Op);
+ handleComparison(C, OrigExpr, Call.getCFGElementRef(),
+ Call.getReturnValue(), Call.getArgSVal(0),
+ Call.getArgSVal(1), Op);
return;
} else if (isRandomIncrOrDecrOperator(Op)) {
const auto *OrigExpr = Call.getOriginExpr();
@@ -443,9 +446,10 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
}
}
-void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
- SVal RetVal, SVal LVal, SVal RVal,
- OverloadedOperatorKind Op) const {
+void IteratorModeling::handleComparison(
+ CheckerContext &C, const Expr *CE,
+ const CFGBlock::ConstCFGElementRef ElemRef, SVal RetVal, SVal LVal,
+ SVal RVal, OverloadedOperatorKind Op) const {
// Record the operands and the operator of the comparison for the next
// evalAssume, if the result is a symbolic expression. If it is a concrete
// value (only one branch is possible), then transfer the state between
@@ -467,7 +471,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
SymbolRef Sym;
if (!LPos || !RPos) {
auto &SymMgr = C.getSymbolManager();
- Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ Sym = SymMgr.conjureSymbol(ElemRef, C.getLocationContext(),
C.getASTContext().LongTy, C.blockCount());
State = assumeNoOverflow(State, Sym, 4);
}
@@ -494,7 +498,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
auto &SymMgr = C.getSymbolManager();
auto *LCtx = C.getLocationContext();
RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
- CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
+ ElemRef, LCtx, C.getASTContext().BoolTy, C.blockCount()));
State = State->BindExpr(CE, LCtx, RetVal);
}
@@ -688,7 +692,8 @@ void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
auto State = C.getState();
const auto *LCtx = C.getLocationContext();
- State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount());
+ State = createIteratorPosition(State, RetVal, Cont, C.getCFGElementRef(),
+ LCtx, C.blockCount());
C.addTransition(State);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 0d1213ddf8b01..ebd7f1a726b09 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1833,8 +1833,10 @@ ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
unsigned Count = C.blockCount();
SValBuilder &SVB = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal = isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
- : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count);
+ DefinedSVal RetVal =
+ isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
+ : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
+ CE->getType(), Count);
return State->BindExpr(CE, C.getLocationContext(), RetVal);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index cc1ced7358710..939a8544e28b7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -931,8 +931,8 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
if (RetVal.isUnknown() ||
(hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
SValBuilder &SVB = C.getSValBuilder();
- RetVal =
- SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
+ RetVal = SVB.conjureSymbolVal(nullptr, Call.getCFGElementRef(), LCtx,
+ ResultTy, C.blockCount());
}
// Bind the value.
diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
index e037719b90298..f19ef750cae8c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -132,7 +132,8 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
auto &SVB = C.getSValBuilder();
const auto *LCtx = C.getLocationContext();
- SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
+ SVal RetVal = SVB.conjureSymbolVal(nullptr, C.getCFGElementRef(), LCtx,
+ CE->getType(), C.blockCount());
SVal Param = State->getSVal(CE->getArg(paramNum), LCtx);
auto StateFound = State->BindExpr(CE, LCtx, RetVal);
@@ -143,8 +144,9 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
// FIXME: Reverse iterators
const auto *Pos = getIteratorPosition(State, Param);
if (Pos) {
- StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
- CE, LCtx, C.blockCount());
+ StateFound =
+ createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
+ C.getCFGElementRef(), LCtx, C.blockCount());
const auto *NewPos = getIteratorPosition(StateFound, RetVal);
assert(NewPos && "Failed to create new iterator position.");
@@ -165,8 +167,9 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
// FIXME: Reverse iterators
Pos = getIteratorPosition(State, Param);
if (Pos) {
- StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
- CE, LCtx, C.blockCount());
+ StateFound =
+ createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
+ C.getCFGElementRef(), LCtx, C.blockCount());
const auto *NewPos = getIteratorPosition(StateFound, RetVal);
assert(NewPos && "Failed to create new iterator position.");
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 321388ad857f4..32f8946ee1c57 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -306,7 +306,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
return false;
const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal(
- Call.getOriginExpr(), C.getLocationContext(),
+ Call.getCFGElementRef(), C.getLocationContext(),
getPointerTypeFromTemplateArg(Call, C), C.blockCount());
const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
@@ -442,8 +442,8 @@ std::pair<SVal, ProgramStateRef> SmartPtrModeling::retrieveOrConjureInnerPtrVal(
const auto *Ptr = State->get<TrackedRegionMap>(ThisRegion);
if (Ptr)
return {*Ptr, State};
- auto Val = C.getSValBuilder().conjureSymbolVal(E, C.getLocationContext(),
- Type, C.blockCount());
+ auto Val = C.getSValBuilder().conjureSymbolVal(
+ C.getCFGElementRef(), C.getLocationContext(), Type, C.blockCount());
State = State->set<TrackedRegionMap>(ThisRegion, Val);
return {Val, State};
}
@@ -853,7 +853,7 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
const LocationContext *LC = C.getLocationContext();
InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
- CallExpr, LC, InnerPointerType, C.blockCount());
+ Call.getCFGElementRef(), LC, InnerPointerType, C.blockCount());
State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 356d63e3e8b80..354797a3325d6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -585,7 +585,7 @@ class StdLibraryFunctionsChecker
CheckerContext &C) const override {
SValBuilder &SVB = C.getSValBuilder();
NonLoc ErrnoSVal =
- SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
+ SVB.conjureSymbolVal(&Tag, Call.getCFGElementRef(),
C.getLocationContext(), C.getASTContext().IntTy,
C.blockCount())
.castAs<NonLoc>();
@@ -1479,7 +1479,8 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
const LocationContext *LC = C.getLocationContext();
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
SVal V = C.getSValBuilder().conjureSymbolVal(
- CE, LC, CE->getType().getCanonicalType(), C.blockCount());
+ Call.getCFGElementRef(), LC, CE->getType().getCanonicalType(),
+ C.blockCount());
State = State->BindExpr(CE, LC, V);
C.addTransition(State);
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 80969ce664530..77671b567e613 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -229,7 +229,8 @@ DefinedSVal makeRetVal(CheckerContext &C, const CallExpr *CE) {
const LocationContext *LCtx = C.getLocationContext();
return C.getSValBuilder()
- .conjureSymbolVal(nullptr, CE, LCtx, C.blockCount())
+ .conjureSymbolVal(nullptr, C.getCFGElementRef(), LCtx, CE->getType(),
+ C.blockCount())
.castAs<DefinedSVal>();
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
index fefe846b6911f..044f9ba61113b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
@@ -207,7 +207,7 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
// Function call will return a pointer to the new symbolic region.
DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal(
- CE, LCtx, CE->getType(), C.blockCount());
+ Call.getCFGElementRef(), LCtx, CE->getType(), C.blockCount());
State = State->BindExpr(CE, LCtx, RetVal);
const auto *SymRegOfRetVal =
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index a4648f5922ef1..d24b98161b4d8 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -82,7 +82,7 @@ void UnarySymExpr::dumpToStream(raw_ostream &os) const {
void SymbolConjured::dumpToStream(raw_ostream &os) const {
os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID();
- if (S)
+ if (const auto *S = getStmt())
os << ", S" << S->getID(LCtx->getDecl()->getASTContext());
else
os << ", no stmt";
>From 15ff87f1e20738e2b04249c7565fefeabe0d4dd1 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sat, 22 Feb 2025 10:25:58 +0000
Subject: [PATCH 04/26] Add Profile for CFGElementRef
---
clang/include/clang/Analysis/CFG.h | 5 +++++
.../clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h | 3 +--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index a7ff38c786a8f..3c0582d648f01 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -695,6 +695,11 @@ class CFGBlock {
void dump() const {
dumpToStream(llvm::errs());
}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(Parent);
+ ID.AddInteger(Index);
+ }
};
template <bool IsReverse, bool IsConst> class ElementRefIterator {
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 4e24c9a81ae1f..2b74e61ad2089 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -125,8 +125,7 @@ class SymbolConjured : public SymbolData {
const LocationContext *LCtx, QualType T, unsigned Count,
const void *SymbolTag) {
profile.AddInteger((unsigned)SymbolConjuredKind);
- // profile.Add(ElemRef);
- // profile.AddPointer(S);
+ profile.Add(ElemRef);
profile.AddPointer(LCtx);
profile.Add(T);
profile.AddInteger(Count);
>From 695beda8f44f1d8ec6e47bb5f1894b527ec93605 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sat, 22 Feb 2025 10:27:19 +0000
Subject: [PATCH 05/26] Add getter for CFGElementRef in SymbolConjured
---
.../clang/StaticAnalyzer/Checkers/SValExplainer.h | 9 +++++++--
.../StaticAnalyzer/Core/PathSensitive/SymbolManager.h | 6 ++++++
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 519d2d5b3676b..2cb5e0123071f 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -113,8 +113,13 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
}
std::string VisitSymbolConjured(const SymbolConjured *S) {
- return "symbol of type '" + S->getType().getAsString() +
- "' conjured at statement '" + printStmt(S->getStmt()) + "'";
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ OS << "symbol of type '" + S->getType().getAsString() +
+ "' conjured at statement '";
+ S->getCFGElementRef()->dumpToStream(OS);
+ OS << "'";
+ return Str;
}
std::string VisitSymbolDerived(const SymbolDerived *S) {
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 2b74e61ad2089..05961f42c02c6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -104,12 +104,18 @@ class SymbolConjured : public SymbolData {
public:
/// It might return null.
+ // TODO: Remove
const Stmt *getStmt() const {
if (auto Stmt = ElemRef->getAs<CFGStmt>()) {
return Stmt->getStmt();
}
return nullptr;
}
+
+ const CFGBlock::ConstCFGElementRef getCFGElementRef() const {
+ return ElemRef;
+ }
+
unsigned getCount() const { return Count; }
/// It might return null.
const void *getTag() const { return SymbolTag; }
>From f94695cc8a2b1dd97a6e7d68ea0aefae4b4b97e3 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sat, 22 Feb 2025 10:28:50 +0000
Subject: [PATCH 06/26] Pass along CFGElementRef in more calls
---
.../Core/PathSensitive/LoopWidening.h | 3 ++-
.../Core/PathSensitive/ProgramState.h | 14 ++++++++-----
.../StaticAnalyzer/Core/PathSensitive/Store.h | 11 ++++++----
.../Checkers/CStringChecker.cpp | 4 ++--
.../StaticAnalyzer/Checkers/ErrnoModeling.cpp | 2 +-
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 2 +-
.../Checkers/SmartPtrModeling.cpp | 2 +-
.../StaticAnalyzer/Checkers/StreamChecker.cpp | 4 ++--
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 21 ++++++++++---------
.../Core/ExprEngineCallAndReturn.cpp | 2 +-
.../lib/StaticAnalyzer/Core/LoopWidening.cpp | 15 ++++++-------
.../lib/StaticAnalyzer/Core/ProgramState.cpp | 14 ++++++-------
clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 18 ++++++++--------
14 files changed, 62 insertions(+), 52 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
index e75228f92a8e5..1354fc058056d 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -27,7 +27,8 @@ namespace ento {
/// by the loop body in any iteration.
ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
const LocationContext *LCtx,
- unsigned BlockCount, const Stmt *LoopStmt);
+ unsigned BlockCount, const Stmt *LoopStmt,
+ const CFGBlock::ConstCFGElementRef ElemRef);
} // end namespace ento
} // end namespace clang
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index a20516b003c7d..80639fe6e3a6d 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H
+#include "clang/Analysis/CFG.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
@@ -313,7 +314,8 @@ class ProgramState : public llvm::FoldingSetNode {
/// be triggered by this event.
///
/// \param Regions the set of regions to be invalidated.
- /// \param E the expression that caused the invalidation.
+ /// \param ElemRef \p CFGBlock::ConstCFGElementRef that caused the
+ /// invalidation.
/// \param BlockCount The number of times the current basic block has been
/// visited.
/// \param CausesPointerEscape the flag is set to true when the invalidation
@@ -325,16 +327,18 @@ class ProgramState : public llvm::FoldingSetNode {
/// \param ITraits information about special handling for particular regions
/// or symbols.
[[nodiscard]] ProgramStateRef
- invalidateRegions(ArrayRef<const MemRegion *> Regions, const Stmt *S,
+ invalidateRegions(ArrayRef<const MemRegion *> Regions,
+ const CFGBlock::ConstCFGElementRef ElemRef,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
const CallEvent *Call = nullptr,
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
[[nodiscard]] ProgramStateRef
- invalidateRegions(ArrayRef<SVal> Values, const Stmt *S, unsigned BlockCount,
- const LocationContext *LCtx, bool CausesPointerEscape,
- InvalidatedSymbols *IS = nullptr,
+ invalidateRegions(ArrayRef<SVal> Values,
+ const CFGBlock::ConstCFGElementRef ElemRef,
+ unsigned BlockCount, const LocationContext *LCtx,
+ bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
const CallEvent *Call = nullptr,
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 332855a3c9c45..217a6d33d48e0 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -14,13 +14,14 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
#include "clang/AST/Type.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
-#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -215,8 +216,9 @@ class StoreManager {
///
/// \param[in] store The initial store.
/// \param[in] Values The values to invalidate.
- /// \param[in] S The current statement being evaluated. Used to conjure
- /// symbols to mark the values of invalidated regions.
+ /// \param[in] ElemRef The current \p CFGBlock::ConstCFGElementRef being
+ /// evaluated. Used to conjure symbols to mark the values of invalidated
+ /// regions.
/// \param[in] Count The current block count. Used to conjure
/// symbols to mark the values of invalidated regions.
/// \param[in] Call The call expression which will be used to determine which
@@ -233,7 +235,8 @@ class StoreManager {
/// even if they do not currently have bindings. Pass \c NULL if this
/// information will not be used.
virtual StoreRef invalidateRegions(
- Store store, ArrayRef<SVal> Values, const Stmt *S, unsigned Count,
+ Store store, ArrayRef<SVal> Values,
+ const CFGBlock::ConstCFGElementRef ElemRef, unsigned Count,
const LocationContext *LCtx, const CallEvent *Call,
InvalidatedSymbols &IS, RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) = 0;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index ea3b815a95bc1..e54576be2ba04 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -1299,8 +1299,8 @@ ProgramStateRef CStringChecker::invalidateBufferAux(
RegionAndSymbolInvalidationTraits ITraits;
bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
- return State->invalidateRegions(R, E, C.blockCount(), LCtx,
- CausesPointerEscape, nullptr, nullptr,
+ return State->invalidateRegions(R, C.getCFGElementRef(), C.blockCount(),
+ LCtx, CausesPointerEscape, nullptr, nullptr,
&ITraits);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
index cc8f1dd44b7e4..ee7c0adf5aa9c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
@@ -260,7 +260,7 @@ ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
if (!ErrnoR)
return State;
- State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
+ State = State->invalidateRegions(ErrnoR, C.getCFGElementRef(), C.blockCount(),
C.getLocationContext(), false);
if (!State)
return nullptr;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index ebd7f1a726b09..825bb977d7e60 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -2306,7 +2306,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
// Assume that after memory is freed, it contains unknown values. This
// conforts languages standards, since reading from freed memory is considered
// UB and may result in arbitrary value.
- State = State->invalidateRegions({location}, Call.getOriginExpr(),
+ State = State->invalidateRegions({location}, C.getCFGElementRef(),
C.blockCount(), C.getLocationContext(),
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr);
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 32f8946ee1c57..7ccb9210e4c58 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -530,7 +530,7 @@ bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call,
if (!StreamThisRegion)
return false;
State =
- State->invalidateRegions({StreamThisRegion}, Call.getOriginExpr(),
+ State->invalidateRegions({StreamThisRegion}, C.getCFGElementRef(),
C.blockCount(), C.getLocationContext(), false);
State =
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal);
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 77671b567e613..49e332eb2a44a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -859,7 +859,7 @@ escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call,
ITraits.setTrait(Element, DoNotInvalidateSuperRegion);
}
return State->invalidateRegions(
- EscapingVals, Call.getOriginExpr(), BlockCount, LCtx,
+ EscapingVals, Call.getCFGElementRef(), BlockCount, LCtx,
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr, &Call, &ITraits);
}
@@ -869,7 +869,7 @@ static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C,
ArrayRef<unsigned int> EscapingArgs) {
auto GetArgSVal = [&Call](int Idx) { return Call.getArgSVal(Idx); };
auto EscapingVals = to_vector(map_range(EscapingArgs, GetArgSVal));
- State = State->invalidateRegions(EscapingVals, Call.getOriginExpr(),
+ State = State->invalidateRegions(EscapingVals, C.getCFGElementRef(),
C.blockCount(), C.getLocationContext(),
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr);
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index bb4a39f68280c..583315f4f3a90 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -280,7 +280,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
// Invalidate designated regions using the batch invalidation API.
// NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
// global variables.
- return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
+ return Result->invalidateRegions(ValuesToInvalidate, getCFGElementRef(),
BlockCount, getLocationContext(),
/*CausedByPointerEscape*/ true,
/*Symbols=*/nullptr, this, &ETraits);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 6c569e4ccadbe..480e27174a469 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -420,7 +420,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
break;
case SubobjectAdjustment::MemberPointerAdjustment:
// FIXME: Unimplemented.
- State = State->invalidateRegions(Reg, InitWithAdjustments,
+ State = State->invalidateRegions(Reg, getCFGElementRef(),
currBldrCtx->blockCount(), LC, true,
nullptr, nullptr, nullptr);
return State;
@@ -2549,8 +2549,8 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
return;
// Widen.
const LocationContext *LCtx = Pred->getLocationContext();
- ProgramStateRef WidenedState =
- getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term);
+ ProgramStateRef WidenedState = getWidenedLoopState(
+ Pred->getState(), LCtx, BlockCount, Term, getCFGElementRef());
nodeBuilder.generateNode(WidenedState, Pred);
return;
}
@@ -3511,11 +3511,10 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
ValuesToInvalidate.push_back(SubExprVal);
}
- State = State->invalidateRegions(ValuesToInvalidate, AE,
- currBldrCtx->blockCount(),
- LCtx,
- /*CausedByPointerEscape*/true,
- /*Symbols=*/nullptr);
+ State = State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(),
+ currBldrCtx->blockCount(), LCtx,
+ /*CausedByPointerEscape*/ true,
+ /*Symbols=*/nullptr);
SVal ResultVal = UnknownVal();
State = State->BindExpr(AE, LCtx, ResultVal);
@@ -3862,7 +3861,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
if (std::optional<Loc> LV = X.getAs<Loc>())
- state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(),
+ state = state->invalidateRegions(*LV, getCFGElementRef(),
+ currBldrCtx->blockCount(),
Pred->getLocationContext(),
/*CausedByPointerEscape=*/true);
}
@@ -3872,7 +3872,8 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
SVal X = state->getSVal(I, Pred->getLocationContext());
if (std::optional<Loc> LV = X.getAs<Loc>())
- state = state->invalidateRegions(*LV, A, currBldrCtx->blockCount(),
+ state = state->invalidateRegions(*LV, getCFGElementRef(),
+ currBldrCtx->blockCount(),
Pred->getLocationContext(),
/*CausedByPointerEscape=*/true);
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 7207e7950a5bf..9bbfb3710f315 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -788,7 +788,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
RegionAndSymbolInvalidationTraits ITraits;
ITraits.setTrait(TargetR,
RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
- State = State->invalidateRegions(TargetR, E, Count, LCtx,
+ State = State->invalidateRegions(TargetR, getCFGElementRef(), Count, LCtx,
/* CausesPointerEscape=*/false, nullptr,
&Call, &ITraits);
diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
index 9e42801760622..617c8bf559a36 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
@@ -13,10 +13,11 @@
///
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
#include "clang/AST/AST.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
using namespace clang;
using namespace ento;
@@ -43,9 +44,10 @@ static const Expr *getLoopCondition(const Stmt *LoopStmt) {
namespace clang {
namespace ento {
-ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
- const LocationContext *LCtx,
- unsigned BlockCount, const Stmt *LoopStmt) {
+ProgramStateRef
+getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx,
+ unsigned BlockCount, const Stmt *LoopStmt,
+ const CFGBlock::ConstCFGElementRef ElemRef) {
assert((isa<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(LoopStmt)));
@@ -93,9 +95,8 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
}
- return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt),
- BlockCount, LCtx, true, nullptr, nullptr,
- &ITraits);
+ return PrevState->invalidateRegions(Regions, ElemRef, BlockCount, LCtx, true,
+ nullptr, nullptr, &ITraits);
}
} // end namespace ento
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index 34ab2388cbd2f..4d77ee31b5a43 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -148,21 +148,21 @@ typedef ArrayRef<const MemRegion *> RegionList;
typedef ArrayRef<SVal> ValueList;
ProgramStateRef ProgramState::invalidateRegions(
- RegionList Regions, const Stmt *S, unsigned Count,
- const LocationContext *LCtx, bool CausedByPointerEscape,
+ RegionList Regions, const CFGBlock::ConstCFGElementRef ElemRef,
+ unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape,
InvalidatedSymbols *IS, const CallEvent *Call,
RegionAndSymbolInvalidationTraits *ITraits) const {
SmallVector<SVal, 8> Values;
for (const MemRegion *Reg : Regions)
Values.push_back(loc::MemRegionVal(Reg));
- return invalidateRegions(Values, S, Count, LCtx, CausedByPointerEscape, IS,
- Call, ITraits);
+ return invalidateRegions(Values, ElemRef, Count, LCtx, CausedByPointerEscape,
+ IS, Call, ITraits);
}
ProgramStateRef ProgramState::invalidateRegions(
- ValueList Values, const Stmt *S, unsigned Count,
- const LocationContext *LCtx, bool CausedByPointerEscape,
+ ValueList Values, const CFGBlock::ConstCFGElementRef ElemRef,
+ unsigned Count, const LocationContext *LCtx, bool CausedByPointerEscape,
InvalidatedSymbols *IS, const CallEvent *Call,
RegionAndSymbolInvalidationTraits *ITraits) const {
@@ -180,7 +180,7 @@ ProgramStateRef ProgramState::invalidateRegions(
StoreManager::InvalidatedRegions TopLevelInvalidated;
StoreManager::InvalidatedRegions Invalidated;
const StoreRef &NewStore = Mgr.StoreMgr->invalidateRegions(
- getStore(), Values, S, Count, LCtx, Call, *IS, *ITraits,
+ getStore(), Values, ElemRef, Count, LCtx, Call, *IS, *ITraits,
&TopLevelInvalidated, &Invalidated);
ProgramStateRef NewState = makeWithStore(NewStore);
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 88aae1836d20b..b4fe96f32ce8e 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -480,7 +480,8 @@ class RegionStoreManager : public StoreManager {
unsigned Count, const LocationContext *LCtx,
RegionBindingsRef B, InvalidatedRegions *Invalidated);
- StoreRef invalidateRegions(Store store, ArrayRef<SVal> Values, const Stmt *S,
+ StoreRef invalidateRegions(Store store, ArrayRef<SVal> Values,
+ const CFGBlock::ConstCFGElementRef ElemRef,
unsigned Count, const LocationContext *LCtx,
const CallEvent *Call, InvalidatedSymbols &IS,
RegionAndSymbolInvalidationTraits &ITraits,
@@ -1364,7 +1365,8 @@ void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W,
}
StoreRef RegionStoreManager::invalidateRegions(
- Store store, ArrayRef<SVal> Values, const Stmt *S, unsigned Count,
+ Store store, ArrayRef<SVal> Values,
+ const CFGBlock::ConstCFGElementRef ElemRef, unsigned Count,
const LocationContext *LCtx, const CallEvent *Call, InvalidatedSymbols &IS,
RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *TopLevelRegions, InvalidatedRegions *Invalidated) {
@@ -1379,8 +1381,8 @@ StoreRef RegionStoreManager::invalidateRegions(
}
RegionBindingsRef B = getRegionBindings(store);
- InvalidateRegionsWorker W(*this, StateMgr, B, Call->getCFGElementRef(), Count,
- LCtx, IS, ITraits, Invalidated, GlobalsFilter);
+ InvalidateRegionsWorker W(*this, StateMgr, B, ElemRef, Count, LCtx, IS,
+ ITraits, Invalidated, GlobalsFilter);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
@@ -1400,13 +1402,11 @@ StoreRef RegionStoreManager::invalidateRegions(
switch (GlobalsFilter) {
case GFK_All:
B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
- Call->getCFGElementRef(), Count, LCtx, B,
- Invalidated);
+ ElemRef, Count, LCtx, B, Invalidated);
[[fallthrough]];
case GFK_SystemOnly:
- B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
- Call->getCFGElementRef(), Count, LCtx, B,
- Invalidated);
+ B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, ElemRef,
+ Count, LCtx, B, Invalidated);
[[fallthrough]];
case GFK_None:
break;
>From b57a36892d928a17e0d898f7831f334a31784f56 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sat, 22 Feb 2025 10:36:59 +0000
Subject: [PATCH 07/26] Remove some unused code
---
.../Core/PathSensitive/SValBuilder.h | 36 ++-----------------
.../Core/PathSensitive/SymbolManager.h | 23 ------------
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 24 -------------
.../lib/StaticAnalyzer/Core/SymbolManager.cpp | 6 ++--
4 files changed, 4 insertions(+), 85 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 6fb5f15822585..c9fc8ae723258 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -179,21 +179,6 @@ class SValBuilder {
return SymMgr.conjureSymbol(ElemRef, LCtx, type, visitCount, symbolTag);
}
- // const SymbolConjured* conjureSymbol(const Stmt *stmt,
- // const LocationContext *LCtx,
- // QualType type,
- // unsigned visitCount,
- // const void *symbolTag = nullptr) {
- // return SymMgr.conjureSymbol(stmt, LCtx, type, visitCount, symbolTag);
- // }
-
- // const SymbolConjured* conjureSymbol(const Expr *expr,
- // const LocationContext *LCtx,
- // unsigned visitCount,
- // const void *symbolTag = nullptr) {
- // return SymMgr.conjureSymbol(expr, LCtx, visitCount, symbolTag);
- // }
-
/// Construct an SVal representing '0' for the specified type.
DefinedOrUnknownSVal makeZeroVal(QualType type);
@@ -206,10 +191,6 @@ class SValBuilder {
/// The advantage of symbols derived/built from other symbols is that we
/// preserve the relation between related(or even equivalent) expressions, so
/// conjured symbols should be used sparingly.
- // DefinedOrUnknownSVal
- // conjureSymbolVal(const void *symbolTag,
- // const CFGBlock::ConstCFGElementRef elemRef,
- // const LocationContext *LCtx, unsigned count);
DefinedOrUnknownSVal
conjureSymbolVal(const void *symbolTag,
const CFGBlock::ConstCFGElementRef elemRef,
@@ -219,25 +200,12 @@ class SValBuilder {
const LocationContext *LCtx, QualType type,
unsigned visitCount);
- // /// Conjure a symbol representing heap allocated memory region.
- // ///
- // /// Note, the expression should represent a location.
- // DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
- // const LocationContext *LCtx,
- // unsigned Count);
-
- // /// Conjure a symbol representing heap allocated memory region.
- // ///
- // /// Note, now, the expression *doesn't* need to represent a location.
- // /// But the type need to!
- // DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
- // const LocationContext *LCtx,
- // QualType type, unsigned Count);
-
+ /// Conjure a symbol representing heap allocated memory region.
DefinedSVal
getConjuredHeapSymbolVal(const CFGBlock::ConstCFGElementRef elemRef,
const LocationContext *LCtx, QualType type,
unsigned Count);
+
/// Create an SVal representing the result of an alloca()-like call, that is,
/// an AllocaRegion on the stack.
///
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 05961f42c02c6..ebad2db530e55 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -103,15 +103,6 @@ class SymbolConjured : public SymbolData {
}
public:
- /// It might return null.
- // TODO: Remove
- const Stmt *getStmt() const {
- if (auto Stmt = ElemRef->getAs<CFGStmt>()) {
- return Stmt->getStmt();
- }
- return nullptr;
- }
-
const CFGBlock::ConstCFGElementRef getCFGElementRef() const {
return ElemRef;
}
@@ -547,13 +538,6 @@ class SymbolManager {
template <typename SymExprT, typename... Args>
const SymExprT *acquire(Args &&...args);
- // const SymbolConjured *conjureSymbol(const Stmt *E,
- // const LocationContext *LCtx, QualType
- // T, unsigned VisitCount, const void
- // *SymbolTag = nullptr) {
- // return acquire<SymbolConjured>(E, LCtx, T, VisitCount, SymbolTag);
- // }
-
const SymbolConjured *
conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef,
const LocationContext *LCtx, QualType T, unsigned VisitCount,
@@ -562,13 +546,6 @@ class SymbolManager {
return acquire<SymbolConjured>(ElemRef, LCtx, T, VisitCount, SymbolTag);
}
- // const SymbolConjured* conjureSymbol(const Expr *E,
- // const LocationContext *LCtx,
- // unsigned VisitCount,
- // const void *SymbolTag = nullptr) {
- // return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag);
- // }
-
QualType getType(const SymExpr *SE) const {
return SE->getType();
}
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index dd173a35cfd73..23440bdec31c9 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -205,30 +205,6 @@ SValBuilder::conjureSymbolVal(const CFGBlock::ConstCFGElementRef elemRef,
return nonloc::SymbolVal(sym);
}
-// DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
-// const LocationContext
-// *LCtx, unsigned VisitCount)
-// {
-// QualType T = E->getType();
-// return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
-// }
-//
-// DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
-// const LocationContext
-// *LCtx, QualType type,
-// unsigned VisitCount) {
-// assert(Loc::isLocType(type));
-// assert(SymbolManager::canSymbolicate(type));
-// if (type->isNullPtrType()) {
-// // makeZeroVal() returns UnknownVal only in case of FP number, which
-// // is not the case.
-// return makeZeroVal(type).castAs<DefinedSVal>();
-// }
-//
-// SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount);
-// return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
-// }
-
DefinedSVal SValBuilder::getConjuredHeapSymbolVal(
const CFGBlock::ConstCFGElementRef elemRef, const LocationContext *LCtx,
QualType type, unsigned VisitCount) {
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index d24b98161b4d8..5c2cfe164888a 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -82,10 +82,8 @@ void UnarySymExpr::dumpToStream(raw_ostream &os) const {
void SymbolConjured::dumpToStream(raw_ostream &os) const {
os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID();
- if (const auto *S = getStmt())
- os << ", S" << S->getID(LCtx->getDecl()->getASTContext());
- else
- os << ", no stmt";
+ os << ", CFGElemRef";
+ ElemRef->dumpToStream(os);
os << ", #" << Count << '}';
}
>From 8c7912227e4f2d864fd68b5e236e1e288543e133 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 00:12:59 +0000
Subject: [PATCH 08/26] Implement getID for CFGElementRefImpl
---
clang/include/clang/Analysis/CFG.h | 6 ++++++
clang/lib/StaticAnalyzer/Core/SymbolManager.cpp | 6 ++----
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index 3c0582d648f01..a665e313e4c15 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -700,6 +700,12 @@ class CFGBlock {
ID.AddPointer(Parent);
ID.AddInteger(Index);
}
+
+ int64_t getID() const {
+ return Parent->getParent()
+ ->getAllocator()
+ .template identifyKnownAlignedObject<CFGElement>(&*this);
+ }
};
template <bool IsReverse, bool IsConst> class ElementRefIterator {
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 5c2cfe164888a..41df94271c849 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -81,10 +81,8 @@ void UnarySymExpr::dumpToStream(raw_ostream &os) const {
}
void SymbolConjured::dumpToStream(raw_ostream &os) const {
- os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID();
- os << ", CFGElemRef";
- ElemRef->dumpToStream(os);
- os << ", #" << Count << '}';
+ os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID()
+ << ", CFGElemRef" << ElemRef.getID() << ", #" << Count << '}';
}
void SymbolDerived::dumpToStream(raw_ostream &os) const {
>From 30e642b752d9406054496ddefbd8641d323b07bb Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 00:13:14 +0000
Subject: [PATCH 09/26] Remove some more unused code
---
clang/lib/StaticAnalyzer/Core/LoopWidening.cpp | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
index 617c8bf559a36..b34e13ece2631 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
@@ -25,22 +25,6 @@ using namespace clang::ast_matchers;
const auto MatchRef = "matchref";
-/// Return the loops condition Stmt or NULL if LoopStmt is not a loop
-static const Expr *getLoopCondition(const Stmt *LoopStmt) {
- switch (LoopStmt->getStmtClass()) {
- default:
- return nullptr;
- case Stmt::ForStmtClass:
- return cast<ForStmt>(LoopStmt)->getCond();
- case Stmt::WhileStmtClass:
- return cast<WhileStmt>(LoopStmt)->getCond();
- case Stmt::DoStmtClass:
- return cast<DoStmt>(LoopStmt)->getCond();
- case Stmt::CXXForRangeStmtClass:
- return cast<CXXForRangeStmt>(LoopStmt)->getCond();
- }
-}
-
namespace clang {
namespace ento {
>From 1821d5cadfb98dc3bda9effca3f717373b3cfe7c Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 00:55:31 +0000
Subject: [PATCH 10/26] Don't use CFGElementRef from CallEvent, fix some calls
to conjureSymbolVal
---
.../Core/PathSensitive/SValBuilder.h | 4 ++
.../Checkers/CStringChecker.cpp | 41 +++++++++----------
.../Checkers/ContainerModeling.cpp | 34 ++++++++-------
.../Checkers/ErrnoTesterChecker.cpp | 6 +--
.../Checkers/IteratorModeling.cpp | 7 ++--
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 2 +-
.../RetainCountChecker/RetainCountChecker.cpp | 2 +-
.../Checkers/STLAlgorithmModeling.cpp | 5 +--
.../Checkers/SmartPtrModeling.cpp | 4 +-
.../Checkers/StdLibraryFunctionsChecker.cpp | 4 +-
.../StaticAnalyzer/Checkers/StreamChecker.cpp | 27 ++++++------
.../Checkers/cert/InvalidPtrChecker.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 16 ++++----
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 4 +-
.../Core/ExprEngineCallAndReturn.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 35 ++++++++--------
16 files changed, 98 insertions(+), 97 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index c9fc8ae723258..004771bec087c 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -192,6 +192,10 @@ class SValBuilder {
/// preserve the relation between related(or even equivalent) expressions, so
/// conjured symbols should be used sparingly.
DefinedOrUnknownSVal
+ conjureSymbolVal(const void *symbolTag, const Expr *expr,
+ const CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *LCtx, unsigned count);
+ DefinedOrUnknownSVal
conjureSymbolVal(const void *symbolTag,
const CFGBlock::ConstCFGElementRef elemRef,
const LocationContext *LCtx, QualType type, unsigned count);
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index e54576be2ba04..5bd94e31c3df8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -1515,8 +1515,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
// conjure a return value for later.
if (lastElement.isUnknown())
lastElement = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getCFGElementRef(), LCtx,
- Call.getOriginExpr()->getType(), C.blockCount());
+ nullptr, Call.getOriginExpr(), C.getCFGElementRef(), LCtx,
+ C.blockCount());
// The byte after the last byte copied is the return value.
state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
@@ -1666,9 +1666,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
if (State) {
// The return value is the comparison result, which we don't know.
- SVal CmpV = Builder.conjureSymbolVal(
- nullptr, Call.getCFGElementRef(), LCtx,
- Call.getOriginExpr()->getType(), C.blockCount());
+ SVal CmpV =
+ Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ C.getCFGElementRef(), LCtx, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
C.addTransition(State);
}
@@ -1772,8 +1772,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getCFGElementRef(), LCtx,
- Call.getOriginExpr()->getType(), C.blockCount());
+ nullptr, Call.getOriginExpr(), C.getCFGElementRef(), LCtx,
+ C.blockCount());
NonLoc resultNL = result.castAs<NonLoc>();
if (strLengthNL) {
@@ -1797,8 +1797,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getCFGElementRef(), LCtx,
- Call.getOriginExpr()->getType(), C.blockCount());
+ nullptr, C.getCFGElementRef(), LCtx, Call.getOriginExpr()->getType(),
+ C.blockCount());
}
}
@@ -2265,9 +2265,9 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (ReturnEnd && Result.isUnknown()) {
- Result = svalBuilder.conjureSymbolVal(
- nullptr, Call.getCFGElementRef(), LCtx,
- Call.getOriginExpr()->getType(), C.blockCount());
+ Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ C.getCFGElementRef(), LCtx,
+ C.blockCount());
}
}
// Set the return value.
@@ -2366,9 +2366,9 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
const StringLiteral *RightStrLiteral =
getCStringLiteral(C, state, Right.Expression, RightVal);
bool canComputeResult = false;
- SVal resultVal = svalBuilder.conjureSymbolVal(
- nullptr, Call.getCFGElementRef(), LCtx, Call.getOriginExpr()->getType(),
- C.blockCount());
+ SVal resultVal =
+ svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ C.getCFGElementRef(), LCtx, C.blockCount());
if (LeftStrLiteral && RightStrLiteral) {
StringRef LeftStrRef = LeftStrLiteral->getString();
@@ -2475,15 +2475,14 @@ void CStringChecker::evalStrsep(CheckerContext &C,
// further along in the same string, or NULL if there are no more tokens.
State =
State->bindLoc(*SearchStrLoc,
- SVB.conjureSymbolVal(getTag(), Call.getCFGElementRef(),
+ SVB.conjureSymbolVal(getTag(), C.getCFGElementRef(),
LCtx, CharPtrTy, C.blockCount()),
LCtx);
} else {
assert(SearchStrVal.isUnknown());
// Conjure a symbolic value. It's the best we can do.
- Result =
- SVB.conjureSymbolVal(nullptr, Call.getCFGElementRef(), LCtx,
- Call.getOriginExpr()->getType(), C.blockCount());
+ Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ C.getCFGElementRef(), LCtx, C.blockCount());
}
// Set the return value, and finish.
@@ -2527,8 +2526,8 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
SValBuilder &SVB = C.getSValBuilder();
SVal ResultVal =
- SVB.conjureSymbolVal(nullptr, Call.getCFGElementRef(), LCtx,
- Call.getOriginExpr()->getType(), C.blockCount());
+ SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), C.getCFGElementRef(),
+ LCtx, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
C.addTransition(State);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
index 74a7b8e0f54ff..16579a691965b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclTemplate.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -107,12 +108,13 @@ bool frontModifiable(ProgramStateRef State, const MemRegion *Reg);
bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
-ProgramStateRef createContainerBegin(CheckerContext &C, ProgramStateRef State,
- const MemRegion *Cont, const Expr *E,
+ProgramStateRef createContainerBegin(ProgramStateRef State,
+ const MemRegion *Cont,
+ const CFGBlock::ConstCFGElementRef ElemRef,
QualType T, const LocationContext *LCtx,
unsigned BlockCount);
-ProgramStateRef createContainerEnd(CheckerContext &C, ProgramStateRef State,
- const MemRegion *Cont, const Expr *E,
+ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
+ const CFGBlock::ConstCFGElementRef ElemRef,
QualType T, const LocationContext *LCtx,
unsigned BlockCount);
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
@@ -260,9 +262,9 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
auto State = C.getState();
auto BeginSym = getContainerBegin(State, ContReg);
if (!BeginSym) {
- State =
- createContainerBegin(C, State, ContReg, CE, C.getASTContext().LongTy,
- C.getLocationContext(), C.blockCount());
+ State = createContainerBegin(State, ContReg, C.getCFGElementRef(),
+ C.getASTContext().LongTy,
+ C.getLocationContext(), C.blockCount());
BeginSym = getContainerBegin(State, ContReg);
}
State = setIteratorPosition(State, RetVal,
@@ -283,8 +285,9 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
auto State = C.getState();
auto EndSym = getContainerEnd(State, ContReg);
if (!EndSym) {
- State = createContainerEnd(C, State, ContReg, CE, C.getASTContext().LongTy,
- C.getLocationContext(), C.blockCount());
+ State = createContainerEnd(State, ContReg, C.getCFGElementRef(),
+ C.getASTContext().LongTy, C.getLocationContext(),
+ C.blockCount());
EndSym = getContainerEnd(State, ContReg);
}
State = setIteratorPosition(State, RetVal,
@@ -845,8 +848,9 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
return CDataPtr->getEnd();
}
-ProgramStateRef createContainerBegin(CheckerContext &C, ProgramStateRef State,
- const MemRegion *Cont, const Expr *E,
+ProgramStateRef createContainerBegin(ProgramStateRef State,
+ const MemRegion *Cont,
+ const CFGBlock::ConstCFGElementRef ElemRef,
QualType T, const LocationContext *LCtx,
unsigned BlockCount) {
// Only create if it does not exist
@@ -856,7 +860,7 @@ ProgramStateRef createContainerBegin(CheckerContext &C, ProgramStateRef State,
auto &SymMgr = State->getSymbolManager();
const SymbolConjured *Sym =
- SymMgr.conjureSymbol(C.getCFGElementRef(), LCtx, T, BlockCount, "begin");
+ SymMgr.conjureSymbol(ElemRef, LCtx, T, BlockCount, "begin");
State = assumeNoOverflow(State, Sym, 4);
if (CDataPtr) {
@@ -868,8 +872,8 @@ ProgramStateRef createContainerBegin(CheckerContext &C, ProgramStateRef State,
return setContainerData(State, Cont, CData);
}
-ProgramStateRef createContainerEnd(CheckerContext &C, ProgramStateRef State,
- const MemRegion *Cont, const Expr *E,
+ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
+ const CFGBlock::ConstCFGElementRef ElemRef,
QualType T, const LocationContext *LCtx,
unsigned BlockCount) {
// Only create if it does not exist
@@ -879,7 +883,7 @@ ProgramStateRef createContainerEnd(CheckerContext &C, ProgramStateRef State,
auto &SymMgr = State->getSymbolManager();
const SymbolConjured *Sym =
- SymMgr.conjureSymbol(C.getCFGElementRef(), LCtx, T, BlockCount, "end");
+ SymMgr.conjureSymbol(ElemRef, LCtx, T, BlockCount, "end");
State = assumeNoOverflow(State, Sym, 4);
if (CDataPtr) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
index b47787d59fc62..65e3190d2dc22 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
@@ -130,9 +130,9 @@ void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C,
ProgramStateRef StateFailure = State->BindExpr(
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
- DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal(
- nullptr, Call.getCFGElementRef(), C.getLocationContext(),
- Call.getOriginExpr()->getType(), C.blockCount());
+ DefinedOrUnknownSVal ErrnoVal =
+ SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), C.getCFGElementRef(),
+ C.getLocationContext(), C.blockCount());
StateFailure = StateFailure->assume(ErrnoVal, true);
assert(StateFailure && "Failed to assume on an initial value.");
StateFailure =
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index 380991f10f499..12df1fb3d81d0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -356,15 +356,14 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C,
return;
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- handleComparison(C, OrigExpr, Call.getCFGElementRef(),
+ handleComparison(C, OrigExpr, C.getCFGElementRef(),
Call.getReturnValue(), InstCall->getCXXThisVal(),
Call.getArgSVal(0), Op);
return;
}
- handleComparison(C, OrigExpr, Call.getCFGElementRef(),
- Call.getReturnValue(), Call.getArgSVal(0),
- Call.getArgSVal(1), Op);
+ handleComparison(C, OrigExpr, C.getCFGElementRef(), Call.getReturnValue(),
+ Call.getArgSVal(0), Call.getArgSVal(1), Op);
return;
} else if (isRandomIncrOrDecrOperator(Op)) {
const auto *OrigExpr = Call.getOriginExpr();
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 825bb977d7e60..857974be0c582 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1835,7 +1835,7 @@ ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
DefinedSVal RetVal =
isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
- : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
+ : SVB.getConjuredHeapSymbolVal(C.getCFGElementRef(), LCtx,
CE->getType(), Count);
return State->BindExpr(CE, C.getLocationContext(), RetVal);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 939a8544e28b7..e2f98bace3f59 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -931,7 +931,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
if (RetVal.isUnknown() ||
(hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
SValBuilder &SVB = C.getSValBuilder();
- RetVal = SVB.conjureSymbolVal(nullptr, Call.getCFGElementRef(), LCtx,
+ RetVal = SVB.conjureSymbolVal(nullptr, C.getCFGElementRef(), LCtx,
ResultTy, C.blockCount());
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
index f19ef750cae8c..ce424dbfa9b85 100644
--- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -132,8 +132,8 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
auto &SVB = C.getSValBuilder();
const auto *LCtx = C.getLocationContext();
- SVal RetVal = SVB.conjureSymbolVal(nullptr, C.getCFGElementRef(), LCtx,
- CE->getType(), C.blockCount());
+ SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, C.getCFGElementRef(), LCtx,
+ C.blockCount());
SVal Param = State->getSVal(CE->getArg(paramNum), LCtx);
auto StateFound = State->BindExpr(CE, LCtx, RetVal);
@@ -202,4 +202,3 @@ void ento::registerSTLAlgorithmModeling(CheckerManager &Mgr) {
bool ento::shouldRegisterSTLAlgorithmModeling(const CheckerManager &mgr) {
return true;
}
-
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 7ccb9210e4c58..fa4cf3e2ceeba 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -306,7 +306,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
return false;
const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal(
- Call.getCFGElementRef(), C.getLocationContext(),
+ C.getCFGElementRef(), C.getLocationContext(),
getPointerTypeFromTemplateArg(Call, C), C.blockCount());
const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
@@ -853,7 +853,7 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
const LocationContext *LC = C.getLocationContext();
InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
- Call.getCFGElementRef(), LC, InnerPointerType, C.blockCount());
+ C.getCFGElementRef(), LC, InnerPointerType, C.blockCount());
State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 354797a3325d6..633877ada4742 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -585,7 +585,7 @@ class StdLibraryFunctionsChecker
CheckerContext &C) const override {
SValBuilder &SVB = C.getSValBuilder();
NonLoc ErrnoSVal =
- SVB.conjureSymbolVal(&Tag, Call.getCFGElementRef(),
+ SVB.conjureSymbolVal(&Tag, C.getCFGElementRef(),
C.getLocationContext(), C.getASTContext().IntTy,
C.blockCount())
.castAs<NonLoc>();
@@ -1479,7 +1479,7 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
const LocationContext *LC = C.getLocationContext();
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
SVal V = C.getSValBuilder().conjureSymbolVal(
- Call.getCFGElementRef(), LC, CE->getType().getCanonicalType(),
+ C.getCFGElementRef(), LC, CE->getType().getCanonicalType(),
C.blockCount());
State = State->BindExpr(CE, LC, V);
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 49e332eb2a44a..2a890b96fa0e1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -13,6 +13,7 @@
#include "NoOwnershipChangeVisitor.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -229,8 +230,7 @@ DefinedSVal makeRetVal(CheckerContext &C, const CallExpr *CE) {
const LocationContext *LCtx = C.getLocationContext();
return C.getSValBuilder()
- .conjureSymbolVal(nullptr, C.getCFGElementRef(), LCtx, CE->getType(),
- C.blockCount())
+ .conjureSymbolVal(nullptr, CE, C.getCFGElementRef(), LCtx, C.blockCount())
.castAs<DefinedSVal>();
}
@@ -833,11 +833,10 @@ static std::optional<int64_t> getKnownValue(ProgramStateRef State, SVal V) {
/// Invalidate only the requested elements instead of the whole buffer.
/// This is basically a refinement of the more generic 'escapeArgs' or
/// the plain old 'invalidateRegions'.
-static ProgramStateRef
-escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call,
- unsigned BlockCount, const SubRegion *Buffer,
- QualType ElemType, int64_t StartIndex,
- int64_t ElementCount) {
+static ProgramStateRef escapeByStartIndexAndCount(
+ ProgramStateRef State, const CallEvent &Call, unsigned BlockCount,
+ const SubRegion *Buffer, QualType ElemType, int64_t StartIndex,
+ int64_t ElementCount, const CFGBlock::ConstCFGElementRef ElemRef) {
constexpr auto DoNotInvalidateSuperRegion =
RegionAndSymbolInvalidationTraits::InvalidationKinds::
TK_DoNotInvalidateSuperRegion;
@@ -858,10 +857,10 @@ escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call,
EscapingVals.push_back(loc::MemRegionVal(Element));
ITraits.setTrait(Element, DoNotInvalidateSuperRegion);
}
- return State->invalidateRegions(
- EscapingVals, Call.getCFGElementRef(), BlockCount, LCtx,
- /*CausesPointerEscape=*/false,
- /*InvalidatedSymbols=*/nullptr, &Call, &ITraits);
+ return State->invalidateRegions(EscapingVals, ElemRef, BlockCount, LCtx,
+ /*CausesPointerEscape=*/false,
+ /*InvalidatedSymbols=*/nullptr, &Call,
+ &ITraits);
}
static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C,
@@ -1139,9 +1138,9 @@ tryToInvalidateFReadBufferByElements(ProgramStateRef State, CheckerContext &C,
constexpr int MaxInvalidatedElementsLimit = 64;
if (NumCompleteOrIncompleteElementsRead <= MaxInvalidatedElementsLimit) {
- return escapeByStartIndexAndCount(State, Call, C.blockCount(), Buffer,
- ElemTy, *StartIndexVal,
- NumCompleteOrIncompleteElementsRead);
+ return escapeByStartIndexAndCount(
+ State, Call, C.blockCount(), Buffer, ElemTy, *StartIndexVal,
+ NumCompleteOrIncompleteElementsRead, C.getCFGElementRef());
}
}
return nullptr;
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
index 044f9ba61113b..3c8ddacfd78a4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
@@ -207,7 +207,7 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
// Function call will return a pointer to the new symbolic region.
DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal(
- Call.getCFGElementRef(), LCtx, CE->getType(), C.blockCount());
+ C.getCFGElementRef(), LCtx, CE->getType(), C.blockCount());
State = State->BindExpr(CE, LCtx, RetVal);
const auto *SymRegOfRetVal =
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 169983605f5f0..18fdc30b86c94 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -22,7 +22,7 @@ using namespace ento;
using llvm::APSInt;
/// Optionally conjure and return a symbol for offset when processing
-/// an expression \p Expression.
+/// a \p CFGElementRef.
/// If \p Other is a location, conjure a symbol for \p Symbol
/// (offset) if it is unknown so that memory arithmetic always
/// results in an ElementRegion.
@@ -32,7 +32,6 @@ static SVal conjureOffsetSymbolOnLocation(SVal Symbol, SVal Other,
QualType Ty, SValBuilder &svalBuilder,
unsigned Count,
const LocationContext *LCtx) {
- // QualType Ty = Expression->getType();
if (isa<Loc>(Other) && Ty->isIntegralOrEnumerationType() &&
Symbol.isUnknown()) {
return svalBuilder.conjureSymbolVal(elemRef, LCtx, Ty, Count);
@@ -68,8 +67,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// FIXME: Handle structs.
if (RightV.isUnknown()) {
unsigned Count = currBldrCtx->blockCount();
- RightV = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
- B->getRHS()->getType(), Count);
+ RightV = svalBuilder.conjureSymbolVal(nullptr, B->getRHS(),
+ getCFGElementRef(), LCtx, Count);
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
@@ -844,8 +843,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
}
if (!hasValue)
- V = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
- Ex->getType(), currBldrCtx->blockCount());
+ V = svalBuilder.conjureSymbolVal(nullptr, Ex, getCFGElementRef(), LCtx,
+ currBldrCtx->blockCount());
// Generate a new node with the binding from the appropriate path.
B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true));
@@ -1126,9 +1125,8 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
// Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){
- DefinedOrUnknownSVal SymVal =
- svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
- U->getType(), currBldrCtx->blockCount());
+ DefinedOrUnknownSVal SymVal = svalBuilder.conjureSymbolVal(
+ nullptr, U, getCFGElementRef(), LCtx, currBldrCtx->blockCount());
Result = SymVal;
// If the value is a location, ++/-- should always preserve
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 0860402778826..90fbaafe1c1ee 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -970,8 +970,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
symVal = svalBuilder.getConjuredHeapSymbolVal(getCFGElementRef(), LCtx,
CNE->getType(), blockCount);
else
- symVal = svalBuilder.conjureSymbolVal(nullptr, getCFGElementRef(), LCtx,
- CNE->getType(), blockCount);
+ symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, getCFGElementRef(),
+ LCtx, blockCount);
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 9bbfb3710f315..4634c63a5059c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -800,7 +800,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// a regular unknown pointer.
const auto *CNE = dyn_cast<CXXNewExpr>(E);
if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
- R = svalBuilder.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
+ R = svalBuilder.getConjuredHeapSymbolVal(getCFGElementRef(), LCtx,
E->getType(), Count);
const MemRegion *MR = R.getAsRegion()->StripCasts();
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 23440bdec31c9..2f4b281cc2b5e 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -151,24 +151,23 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) {
return nonloc::SymbolVal(sym);
}
-// DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag,
-// const Expr *Ex,
-// const LocationContext
-// *LCtx, unsigned Count) {
-// QualType T = Ex->getType();
-//
-// if (T->isNullPtrType())
-// return makeZeroVal(T);
-//
-// // Compute the type of the result. If the expression is not an R-value, the
-// // result should be a location.
-// QualType ExType = Ex->getType();
-// if (Ex->isGLValue())
-// T =
-// LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType);
-//
-// return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count);
-// }
+DefinedOrUnknownSVal
+SValBuilder::conjureSymbolVal(const void *SymbolTag, const Expr *Ex,
+ const CFGBlock::ConstCFGElementRef elemRef,
+ const LocationContext *LCtx, unsigned Count) {
+ QualType T = Ex->getType();
+
+ if (T->isNullPtrType())
+ return makeZeroVal(T);
+
+ // Compute the type of the result. If the expression is not an R-value, the
+ // result should be a location.
+ QualType ExType = Ex->getType();
+ if (Ex->isGLValue())
+ T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType);
+
+ return conjureSymbolVal(SymbolTag, elemRef, LCtx, T, Count);
+}
DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(
const void *symbolTag, const CFGBlock::ConstCFGElementRef elemRef,
>From ee8c43629846b597e613cbca49d37da46d2e69bc Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 01:08:03 +0000
Subject: [PATCH 11/26] Fix another call to conjureSymbolVal
---
clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 5bd94e31c3df8..41a13e2e8efcb 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -1797,7 +1797,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, C.getCFGElementRef(), LCtx, Call.getOriginExpr()->getType(),
+ nullptr, Call.getOriginExpr(), C.getCFGElementRef(), LCtx,
C.blockCount());
}
}
>From 9f59e500766a7239e3e44b9233b895042401c5e0 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 01:15:01 +0000
Subject: [PATCH 12/26] Remove a redundant parameter in handleComparison
---
.../Checkers/IteratorModeling.cpp | 25 ++++++++-----------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index 12df1fb3d81d0..f2161e8698f13 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -99,8 +99,7 @@ class IteratorModeling
const Expr *OrigExpr,
const AdvanceFn *Handler) const;
- void handleComparison(CheckerContext &C, const Expr *CE,
- const CFGBlock::ConstCFGElementRef ElemRef, SVal RetVal,
+ void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
SVal LVal, SVal RVal, OverloadedOperatorKind Op) const;
void processComparison(CheckerContext &C, ProgramStateRef State,
SymbolRef Sym1, SymbolRef Sym2, SVal RetVal,
@@ -272,7 +271,7 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
if (isSimpleComparisonOperator(BO->getOpcode())) {
SVal Result = State->getSVal(BO, C.getLocationContext());
- handleComparison(C, BO, C.getCFGElementRef(), Result, LVal, RVal,
+ handleComparison(C, BO, Result, LVal, RVal,
BinaryOperator::getOverloadedOperator(OK));
} else if (isRandomIncrOrDecrOperator(OK)) {
// In case of operator+ the iterator can be either on the LHS (eg.: it + 1),
@@ -356,14 +355,13 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C,
return;
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- handleComparison(C, OrigExpr, C.getCFGElementRef(),
- Call.getReturnValue(), InstCall->getCXXThisVal(),
- Call.getArgSVal(0), Op);
+ handleComparison(C, OrigExpr, Call.getReturnValue(),
+ InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
return;
}
- handleComparison(C, OrigExpr, C.getCFGElementRef(), Call.getReturnValue(),
- Call.getArgSVal(0), Call.getArgSVal(1), Op);
+ handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
+ Call.getArgSVal(1), Op);
return;
} else if (isRandomIncrOrDecrOperator(Op)) {
const auto *OrigExpr = Call.getOriginExpr();
@@ -445,10 +443,9 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
}
}
-void IteratorModeling::handleComparison(
- CheckerContext &C, const Expr *CE,
- const CFGBlock::ConstCFGElementRef ElemRef, SVal RetVal, SVal LVal,
- SVal RVal, OverloadedOperatorKind Op) const {
+void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
+ SVal RetVal, SVal LVal, SVal RVal,
+ OverloadedOperatorKind Op) const {
// Record the operands and the operator of the comparison for the next
// evalAssume, if the result is a symbolic expression. If it is a concrete
// value (only one branch is possible), then transfer the state between
@@ -470,7 +467,7 @@ void IteratorModeling::handleComparison(
SymbolRef Sym;
if (!LPos || !RPos) {
auto &SymMgr = C.getSymbolManager();
- Sym = SymMgr.conjureSymbol(ElemRef, C.getLocationContext(),
+ Sym = SymMgr.conjureSymbol(C.getCFGElementRef(), C.getLocationContext(),
C.getASTContext().LongTy, C.blockCount());
State = assumeNoOverflow(State, Sym, 4);
}
@@ -497,7 +494,7 @@ void IteratorModeling::handleComparison(
auto &SymMgr = C.getSymbolManager();
auto *LCtx = C.getLocationContext();
RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
- ElemRef, LCtx, C.getASTContext().BoolTy, C.blockCount()));
+ C.getCFGElementRef(), LCtx, C.getASTContext().BoolTy, C.blockCount()));
State = State->BindExpr(CE, LCtx, RetVal);
}
>From 6150241ced95413a473c7f480e8678f4802b98d0 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 01:45:32 +0000
Subject: [PATCH 13/26] Fix getID (?)
---
clang/include/clang/Analysis/CFG.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index a665e313e4c15..b37e237c9c73b 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -704,7 +704,8 @@ class CFGBlock {
int64_t getID() const {
return Parent->getParent()
->getAllocator()
- .template identifyKnownAlignedObject<CFGElement>(&*this);
+ .template identifyKnownAlignedObject<CFGElement>(
+ &*(Parent->begin() + Index));
}
};
>From 43b1b42f3e53e2c71b0fcb6ad9ed433173cca35f Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 02:15:47 +0000
Subject: [PATCH 14/26] Fix tests
---
clang/test/Analysis/class-object-state-dump.m | 4 ++--
clang/test/Analysis/container-modeling.cpp | 8 ++++----
clang/test/Analysis/ctor-trivial-copy.cpp | 8 ++++----
clang/test/Analysis/dump_egraph.cpp | 5 ++---
clang/test/Analysis/iterator-modeling.cpp | 8 ++++----
clang/test/Analysis/malloc.c | 4 ++--
clang/test/Analysis/trivial-copy-struct.cpp | 2 +-
7 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/clang/test/Analysis/class-object-state-dump.m b/clang/test/Analysis/class-object-state-dump.m
index 740e517b83020..f0f39c1c409c7 100644
--- a/clang/test/Analysis/class-object-state-dump.m
+++ b/clang/test/Analysis/class-object-state-dump.m
@@ -28,8 +28,8 @@ + (void)test {
clang_analyzer_printState();
// CHECK: "class_object_types": [
- // CHECK-NEXT: { "symbol": "conj_$[[#]]{Class, LC[[#]], S[[#]], #[[#]]}", "dyn_type": "Child", "sub_classable": true },
- // CHECK-NEXT: { "symbol": "conj_$[[#]]{Class, LC[[#]], S[[#]], #[[#]]}", "dyn_type": "Child", "sub_classable": true }
+ // CHECK-NEXT: { "symbol": "conj_$[[#]]{Class, LC[[#]], CFGElemRef[[#]], #[[#]]}", "dyn_type": "Child", "sub_classable": true },
+ // CHECK-NEXT: { "symbol": "conj_$[[#]]{Class, LC[[#]], CFGElemRef[[#]], #[[#]]}", "dyn_type": "Child", "sub_classable": true }
// CHECK-NEXT: ]
// Let's make sure that the information is not GC'd away.
diff --git a/clang/test/Analysis/container-modeling.cpp b/clang/test/Analysis/container-modeling.cpp
index bf4a12a0e0fe2..46e7d91d46ccf 100644
--- a/clang/test/Analysis/container-modeling.cpp
+++ b/clang/test/Analysis/container-modeling.cpp
@@ -196,7 +196,7 @@ void pop_front(std::list<int> &L, int n) {
void push_back() {
std::vector<int> V;
V.end();
-
+
clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()");
V.push_back(1); // expected-note{{Container 'V' extended to the back by 1 position}}
@@ -251,15 +251,15 @@ void print_state(std::vector<int> &V) {
// CHECK: "checker_messages": [
// CHECK-NEXT: { "checker": "alpha.cplusplus.ContainerModeling", "messages": [
// CHECK-NEXT: "Container Data :",
-// CHECK-NEXT: "SymRegion{reg_$[[#]]<std::vector<int> & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. <Unknown> ]"
+// CHECK-NEXT: "SymRegion{reg_$[[#]]<std::vector<int> & V>} : [ conj_$[[#]]{long, LC[[#]], CFGElemRef[[#]], #[[#]]} .. <Unknown> ]"
// CHECK-NEXT: ]}
V.cend();
clang_analyzer_printState();
-
+
// CHECK: "checker_messages": [
// CHECK-NEXT: { "checker": "alpha.cplusplus.ContainerModeling", "messages": [
// CHECK-NEXT: "Container Data :",
-// CHECK-NEXT: "SymRegion{reg_$[[#]]<std::vector<int> & V>} : [ conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} .. conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]} ]"
+// CHECK-NEXT: "SymRegion{reg_$[[#]]<std::vector<int> & V>} : [ conj_$[[#]]{long, LC[[#]], CFGElemRef[[#]], #[[#]]} .. conj_$[[#]]{long, LC[[#]], CFGElemRef[[#]], #[[#]]} ]"
// CHECK-NEXT: ]}
}
diff --git a/clang/test/Analysis/ctor-trivial-copy.cpp b/clang/test/Analysis/ctor-trivial-copy.cpp
index 45c8ca4c51776..14f2a7c9d2686 100644
--- a/clang/test/Analysis/ctor-trivial-copy.cpp
+++ b/clang/test/Analysis/ctor-trivial-copy.cpp
@@ -21,11 +21,11 @@ struct empty {
void test_copy_return() {
aggr s1 = {1, 2};
aggr const& cr1 = aggr(s1);
- clang_analyzer_dump_lref(cr1); // expected-warning-re {{&lifetime_extended_object{aggr, cr1, S{{[0-9]+}}} }}
+ clang_analyzer_dump_lref(cr1); // expected-warning-re {{&lifetime_extended_object{aggr, cr1, CFGElemRef{{[0-9]+}}} }}
empty s2;
empty const& cr2 = empty{s2};
- clang_analyzer_dump_lref(cr2); // expected-warning-re {{&lifetime_extended_object{empty, cr2, S{{[0-9]+}}} }}
+ clang_analyzer_dump_lref(cr2); // expected-warning-re {{&lifetime_extended_object{empty, cr2, CFGElemRef{{[0-9]+}}} }}
}
void test_assign_return() {
@@ -64,7 +64,7 @@ void _01_empty_structs() {
// CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$
// CHECK-NEXT: ]},
// CHECK-NEXT: { "cluster": "Empty", "pointer": "0x{{[0-9a-f]+}}", "items": [
- // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ:conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+}]]" }
+ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ:conj_\$[0-9]+{int, LC[0-9]+, CFGElemRef[0-9]+, #[0-9]+}]]" }
// CHECK-NEXT: ]},
// CHECK-NEXT: { "cluster": "Empty2", "pointer": "0x{{[0-9a-f]+}}", "items": [
// CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[EMPTY_CONJ]]" }
@@ -101,7 +101,7 @@ void _02_structs_with_members() {
// CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "conj_$
// CHECK-NEXT: ]},
// CHECK-NEXT: { "cluster": "Aggr", "pointer": "0x{{[0-9a-f]+}}", "items": [
- // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ:conj_\$[0-9]+{int, LC[0-9]+, S[0-9]+, #[0-9]+}]]" }
+ // CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ:conj_\$[0-9]+{int, LC[0-9]+, CFGElemRef[0-9]+, #[0-9]+}]]" }
// CHECK-NEXT: ]},
// CHECK-NEXT: { "cluster": "Aggr2", "pointer": "0x{{[0-9a-f]+}}", "items": [
// CHECK-NEXT: { "kind": "Default", "offset": 0, "value": "[[AGGR_CONJ]]" }
diff --git a/clang/test/Analysis/dump_egraph.cpp b/clang/test/Analysis/dump_egraph.cpp
index 13459699a06f6..dc9ff5743e684 100644
--- a/clang/test/Analysis/dump_egraph.cpp
+++ b/clang/test/Analysis/dump_egraph.cpp
@@ -21,7 +21,6 @@ void foo() {
// CHECK: \"location_context\": \"#0 Call\", \"calling\": \"T::T\", \"location\": \{ \"line\": 15, \"column\": 5, \"file\": \"{{.*}}dump_egraph.cpp\" \}, \"items\": [\l \{ \"init_id\": {{[0-9]+}}, \"kind\": \"construct into member variable\", \"argument_index\": null, \"pretty\": \"s\", \"value\": \"&t.s\"
-// CHECK: \"cluster\": \"t\", \"pointer\": \"{{0x[0-9a-f]+}}\", \"items\": [\l \{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$3\{int, LC5, no stmt, #1\}\"
-
-// CHECK: \"dynamic_types\": [\l \{ \"region\": \"HeapSymRegion\{conj_$1\{S *, LC1, S{{[0-9]+}}, #1\}\}\", \"dyn_type\": \"S\", \"sub_classable\": false \}\l
+// CHECK: \"cluster\": \"t\", \"pointer\": \"{{0x[0-9a-f]+}}\", \"items\": [\l \{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$3\{int, LC5, CFGElemRef{{[0-9=+]}}, #1\}\"
+// CHECK: \"dynamic_types\": [\l \{ \"region\": \"HeapSymRegion\{conj_$1\{S *, LC1, CFGElemRef{{[0-9]+}}, #1\}\}\", \"dyn_type\": \"S\", \"sub_classable\": false \}\l
diff --git a/clang/test/Analysis/iterator-modeling.cpp b/clang/test/Analysis/iterator-modeling.cpp
index 78882da4431fd..453878a8ea093 100644
--- a/clang/test/Analysis/iterator-modeling.cpp
+++ b/clang/test/Analysis/iterator-modeling.cpp
@@ -2035,8 +2035,8 @@ void print_state(std::vector<int> &V) {
// CHECK: "checker_messages": [
// CHECK: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [
// CHECK-NEXT: "Iterator Positions :",
- // CHECK-NEXT: "conj_$[[#]]{int, LC[[#]], S[[#]], #[[#]]} : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}",
- // CHECK-NEXT: "i0 : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}"
+ // CHECK-NEXT: "conj_$[[#]]{int, LC[[#]], CFGElemRef[[#]], #[[#]]} : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], CFGElemRef[[#]], #[[#]]}",
+ // CHECK-NEXT: "i0 : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], CFGElemRef[[#]], #[[#]]}"
// CHECK-NEXT: ]}
*i0;
@@ -2046,8 +2046,8 @@ void print_state(std::vector<int> &V) {
// CHECK: "checker_messages": [
// CHECK: { "checker": "alpha.cplusplus.IteratorModeling", "messages": [
// CHECK-NEXT: "Iterator Positions :",
- // CHECK-NEXT: "conj_$[[#]]{int, LC[[#]], S[[#]], #[[#]]} : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}",
- // CHECK-NEXT: "i1 : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], S[[#]], #[[#]]}"
+ // CHECK-NEXT: "conj_$[[#]]{int, LC[[#]], CFGElemRef[[#]], #[[#]]} : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], CFGElemRef[[#]], #[[#]]}",
+ // CHECK-NEXT: "i1 : Valid ; Container == SymRegion{reg_$[[#]]<std::vector<int> & V>} ; Offset == conj_$[[#]]{long, LC[[#]], CFGElemRef[[#]], #[[#]]}"
// CHECK-NEXT: ]}
*i1;
diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c
index 0dc667bc1ed50..bfacedaa193e4 100644
--- a/clang/test/Analysis/malloc.c
+++ b/clang/test/Analysis/malloc.c
@@ -1954,9 +1954,9 @@ int conjure(void);
void testExtent(void) {
int x = conjure();
clang_analyzer_dump(x);
- // expected-warning-re at -1 {{{{^conj_\$[[:digit:]]+{int, LC1, S[[:digit:]]+, #1}}}}}}
+ // expected-warning-re at -1 {{{{^conj_\$[[:digit:]]+{int, LC1, CFGElemRef[[:digit:]]+, #1}}}}}}
int *p = (int *)malloc(x);
clang_analyzer_dumpExtent(p);
- // expected-warning-re at -1 {{{{^conj_\$[[:digit:]]+{int, LC1, S[[:digit:]]+, #1}}}}}}
+ // expected-warning-re at -1 {{{{^conj_\$[[:digit:]]+{int, LC1, CFGElemRef[[:digit:]]+, #1}}}}}}
free(p);
}
diff --git a/clang/test/Analysis/trivial-copy-struct.cpp b/clang/test/Analysis/trivial-copy-struct.cpp
index b2da777541aba..8583f64d73883 100644
--- a/clang/test/Analysis/trivial-copy-struct.cpp
+++ b/clang/test/Analysis/trivial-copy-struct.cpp
@@ -25,7 +25,7 @@ void copy_on_heap(Node* n1) {
Node* n2 = new Node(*n1);
clang_analyzer_dump(n1); // expected-warning-re {{&SymRegion{reg_${{[0-9]+}}<Node * n1>}}}
- clang_analyzer_dump(n2); // expected-warning-re {{&HeapSymRegion{conj_${{[0-9]+}}{Node *, LC{{[0-9]+}}, S{{[0-9]+}}, #{{[0-9]+}}}}}}
+ clang_analyzer_dump(n2); // expected-warning-re {{&HeapSymRegion{conj_${{[0-9]+}}{Node *, LC{{[0-9]+}}, CFGElemRef{{[0-9]+}}, #{{[0-9]+}}}}}}
clang_analyzer_dump(n1->ptr); // expected-warning-re {{&SymRegion{reg_${{[0-9]+}}<int * Element{SymRegion{reg_${{[0-9]+}}<Node * n1>},0 S64b,struct Node}.ptr>}}}
clang_analyzer_dump(n2->ptr); // expected-warning-re {{&SymRegion{reg_${{[0-9]+}}<int * Element{SymRegion{reg_${{[0-9]+}}<Node * n1>},0 S64b,struct Node}.ptr>}}}
>From 3394012a8392b1c8d470f602ab6b6c7a3ec630e2 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 03:18:06 +0000
Subject: [PATCH 15/26] Fix more tests
---
clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h | 5 +++++
clang/test/Analysis/ctor-trivial-copy.cpp | 4 ++--
clang/test/Analysis/dump_egraph.cpp | 2 +-
.../test/Analysis/exploded-graph-rewriter/dynamic_types.cpp | 2 +-
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index 2cb5e0123071f..c7a63cdcfa229 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -118,6 +118,11 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
OS << "symbol of type '" + S->getType().getAsString() +
"' conjured at statement '";
S->getCFGElementRef()->dumpToStream(OS);
+ // HACK: dumpToStream will output a new line in the end, this is
+ // undesireable, thus we remove it.
+ if (Str.back() == '\n') {
+ Str.pop_back();
+ }
OS << "'";
return Str;
}
diff --git a/clang/test/Analysis/ctor-trivial-copy.cpp b/clang/test/Analysis/ctor-trivial-copy.cpp
index 14f2a7c9d2686..eed5f1a93f81e 100644
--- a/clang/test/Analysis/ctor-trivial-copy.cpp
+++ b/clang/test/Analysis/ctor-trivial-copy.cpp
@@ -21,11 +21,11 @@ struct empty {
void test_copy_return() {
aggr s1 = {1, 2};
aggr const& cr1 = aggr(s1);
- clang_analyzer_dump_lref(cr1); // expected-warning-re {{&lifetime_extended_object{aggr, cr1, CFGElemRef{{[0-9]+}}} }}
+ clang_analyzer_dump_lref(cr1); // expected-warning-re {{&lifetime_extended_object{aggr, cr1, S{{[0-9]+}}} }}
empty s2;
empty const& cr2 = empty{s2};
- clang_analyzer_dump_lref(cr2); // expected-warning-re {{&lifetime_extended_object{empty, cr2, CFGElemRef{{[0-9]+}}} }}
+ clang_analyzer_dump_lref(cr2); // expected-warning-re {{&lifetime_extended_object{empty, cr2, S{{[0-9]+}}} }}
}
void test_assign_return() {
diff --git a/clang/test/Analysis/dump_egraph.cpp b/clang/test/Analysis/dump_egraph.cpp
index dc9ff5743e684..313158fe1b7a5 100644
--- a/clang/test/Analysis/dump_egraph.cpp
+++ b/clang/test/Analysis/dump_egraph.cpp
@@ -21,6 +21,6 @@ void foo() {
// CHECK: \"location_context\": \"#0 Call\", \"calling\": \"T::T\", \"location\": \{ \"line\": 15, \"column\": 5, \"file\": \"{{.*}}dump_egraph.cpp\" \}, \"items\": [\l \{ \"init_id\": {{[0-9]+}}, \"kind\": \"construct into member variable\", \"argument_index\": null, \"pretty\": \"s\", \"value\": \"&t.s\"
-// CHECK: \"cluster\": \"t\", \"pointer\": \"{{0x[0-9a-f]+}}\", \"items\": [\l \{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$3\{int, LC5, CFGElemRef{{[0-9=+]}}, #1\}\"
+// CHECK: \"cluster\": \"t\", \"pointer\": \"{{0x[0-9a-f]+}}\", \"items\": [\l \{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$3\{int, LC5, CFGElemRef{{[0-9]+}}, #1\}\"
// CHECK: \"dynamic_types\": [\l \{ \"region\": \"HeapSymRegion\{conj_$1\{S *, LC1, CFGElemRef{{[0-9]+}}, #1\}\}\", \"dyn_type\": \"S\", \"sub_classable\": false \}\l
diff --git a/clang/test/Analysis/exploded-graph-rewriter/dynamic_types.cpp b/clang/test/Analysis/exploded-graph-rewriter/dynamic_types.cpp
index 01914a86ad4a5..6db74fcfd27ef 100644
--- a/clang/test/Analysis/exploded-graph-rewriter/dynamic_types.cpp
+++ b/clang/test/Analysis/exploded-graph-rewriter/dynamic_types.cpp
@@ -10,7 +10,7 @@ void test() {
// CHECK: Dynamic Types:
// CHECK-SAME: <tr><td align="left"><table border="0"><tr>
// CHECK-SAME: <td align="left">HeapSymRegion\{conj_$1\{S *, LC1,
- // CHECK-SAME: S{{[0-9]*}}, #1\}\}</td>
+ // CHECK-SAME: CFGElemRef{{[0-9]*}}, #1\}\}</td>
// CHECK-SAME: <td align="left">S</td>
// CHECK-SAME: </tr></table></td></tr>
new S;
>From 7ef2ea59add428c19bd64fa32862afeaf62590a4 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Sun, 23 Feb 2025 14:36:49 +0000
Subject: [PATCH 16/26] Fix one more test
---
clang/test/Analysis/explain-svals.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/Analysis/explain-svals.cpp b/clang/test/Analysis/explain-svals.cpp
index d1615e6cc6c9a..defca68ff1e7c 100644
--- a/clang/test/Analysis/explain-svals.cpp
+++ b/clang/test/Analysis/explain-svals.cpp
@@ -52,7 +52,7 @@ void test_2(char *ptr, int ext) {
clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob_ptr'$}}}}
clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}}
int *x = new int[ext];
- clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}}
+ clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at statement 'CFGNewAllocator\(int \*\)'$}}}}
// Sic! What gets computed is the extent of the element-region.
clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^\(argument 'ext'\) \* 4$}}}}
delete[] x;
@@ -99,8 +99,8 @@ class C {
} // end of anonymous namespace
void test_6() {
- clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure_S\(\)'$}}}}
- clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
+ clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure_S\(\) \(CXXRecordTypedCall, \+0\)'$}}}}
+ clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure_S\(\) \(CXXRecordTypedCall, \)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
}
class C_top_level {
>From 8bf4bf8380f99ea584aa0eb08c24cc7c323518bf Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 20:14:18 +0000
Subject: [PATCH 17/26] Fix nullptr in CFGBlock::getID
---
clang/include/clang/Analysis/CFG.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index b37e237c9c73b..38c46e1285459 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -702,6 +702,9 @@ class CFGBlock {
}
int64_t getID() const {
+ if (Parent == nullptr || Parent->getParent() == nullptr) {
+ return 0;
+ }
return Parent->getParent()
->getAllocator()
.template identifyKnownAlignedObject<CFGElement>(
>From 7681e48a99e5dbd99a2b5da64a8b1bf2f2921a53 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 20:34:41 +0000
Subject: [PATCH 18/26] Put CFGElementRef printing in a helper function
---
.../StaticAnalyzer/Checkers/SValExplainer.h | 29 +++++++++++--------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
index c7a63cdcfa229..b19cc78283d9e 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ b/clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -19,6 +19,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cctype>
namespace clang {
@@ -29,6 +31,18 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
ASTContext &ACtx;
ProgramStateRef State;
+ std::string printCFGElementRef(const CFGBlock::ConstCFGElementRef ElemRef) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ ElemRef->dumpToStream(OS);
+ // HACK: `CFGBlock::ConstCFGElementRef::dumpToStream` contains a new line
+ // character in the end of the string, we don't want it so we remove it here.
+ while (!Str.empty() && std::isspace(Str.back())) {
+ Str.pop_back();
+ }
+ return Str;
+ }
+
std::string printStmt(const Stmt *S) {
std::string Str;
llvm::raw_string_ostream OS(Str);
@@ -113,18 +127,9 @@ class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
}
std::string VisitSymbolConjured(const SymbolConjured *S) {
- std::string Str;
- llvm::raw_string_ostream OS(Str);
- OS << "symbol of type '" + S->getType().getAsString() +
- "' conjured at statement '";
- S->getCFGElementRef()->dumpToStream(OS);
- // HACK: dumpToStream will output a new line in the end, this is
- // undesireable, thus we remove it.
- if (Str.back() == '\n') {
- Str.pop_back();
- }
- OS << "'";
- return Str;
+ return "symbol of type '" + S->getType().getAsString() +
+ "' conjured at statement '" +
+ printCFGElementRef(S->getCFGElementRef()) + "'";
}
std::string VisitSymbolDerived(const SymbolDerived *S) {
>From 64517629da5346a0e2d1a5679913639a5e551f9d Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 20:35:34 +0000
Subject: [PATCH 19/26] Remove redundant comment in CheckerContext
---
.../clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 02bd4a91961a9..c9b3096b28672 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -151,7 +151,6 @@ class CheckerContext {
return Pred->getSVal(S);
}
- /// Get the CFG Element Ref from the ExprEngine
CFGBlock::ConstCFGElementRef getCFGElementRef() const {
return Eng.getCFGElementRef();
}
>From 2ac861fc76a91dc92d2a099699727ce8ac18e489 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 20:37:27 +0000
Subject: [PATCH 20/26] Remove redundant argument in LoopWidening
---
.../clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h | 2 +-
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 2 +-
clang/lib/StaticAnalyzer/Core/LoopWidening.cpp | 5 +----
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
index 1354fc058056d..e82bbcb2b73f2 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -27,7 +27,7 @@ namespace ento {
/// by the loop body in any iteration.
ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
const LocationContext *LCtx,
- unsigned BlockCount, const Stmt *LoopStmt,
+ unsigned BlockCount,
const CFGBlock::ConstCFGElementRef ElemRef);
} // end namespace ento
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 480e27174a469..bec5980a5b3cd 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2550,7 +2550,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
// Widen.
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef WidenedState = getWidenedLoopState(
- Pred->getState(), LCtx, BlockCount, Term, getCFGElementRef());
+ Pred->getState(), LCtx, BlockCount, getCFGElementRef());
nodeBuilder.generateNode(WidenedState, Pred);
return;
}
diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
index b34e13ece2631..f28b0ae9cec85 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
@@ -30,11 +30,8 @@ namespace ento {
ProgramStateRef
getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx,
- unsigned BlockCount, const Stmt *LoopStmt,
+ unsigned BlockCount,
const CFGBlock::ConstCFGElementRef ElemRef) {
-
- assert((isa<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(LoopStmt)));
-
// Invalidate values in the current state.
// TODO Make this more conservative by only invalidating values that might
// be modified by the body of the loop.
>From 5be1f5b03ef20c41d4c2aa953f252c992e5e3317 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 20:45:08 +0000
Subject: [PATCH 21/26] Remove a stale FIXME in SymbolManager.h
---
.../clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h | 5 -----
1 file changed, 5 deletions(-)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index ebad2db530e55..6184187ccc4d8 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -93,11 +93,6 @@ class SymbolConjured : public SymbolData {
const void *symbolTag)
: SymbolData(SymbolConjuredKind, sym), ElemRef(elemRef), T(t),
Count(count), LCtx(lctx), SymbolTag(symbolTag) {
- // FIXME: 's' might be a nullptr if we're conducting invalidation
- // that was caused by a destructor call on a temporary object,
- // which has no statement associated with it.
- // Due to this, we might be creating the same invalidation symbol for
- // two different invalidation passes (for two different temporaries).
assert(lctx);
assert(isValidTypeForSymbol(t));
}
>From 4e93a5d4c17ca3b4fa46a43e5908930c84e4292a Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 20:54:06 +0000
Subject: [PATCH 22/26] Remove unused parameters in CStringChecker
---
.../Checkers/CStringChecker.cpp | 38 +++++++++----------
1 file changed, 17 insertions(+), 21 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 41a13e2e8efcb..3625ad80dff4f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -277,24 +277,24 @@ class CStringChecker : public Checker< eval::Call,
QualType SizeTy);
/// Operation never overflows, do not invalidate the super region.
- static ProgramStateRef invalidateDestinationBufferNeverOverflows(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV);
+ static ProgramStateRef
+ invalidateDestinationBufferNeverOverflows(CheckerContext &C,
+ ProgramStateRef S, SVal BufV);
/// We do not know whether the operation can overflow (e.g. size is unknown),
/// invalidate the super region and escape related pointers.
static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV);
+ CheckerContext &C, ProgramStateRef S, SVal BufV);
/// Invalidate the source buffer for escaping pointers.
static ProgramStateRef invalidateSourceBuffer(CheckerContext &C,
- ProgramStateRef S,
- const Expr *BufE, SVal BufV);
+ ProgramStateRef S, SVal BufV);
/// @param InvalidationTraitOperations Determine how to invlidate the
/// MemRegion by setting the invalidation traits. Return true to cause pointer
/// escape, or false otherwise.
static ProgramStateRef invalidateBufferAux(
- CheckerContext &C, ProgramStateRef State, const Expr *Ex, SVal V,
+ CheckerContext &C, ProgramStateRef State, SVal V,
llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &,
const MemRegion *)>
InvalidationTraitOperations);
@@ -1227,22 +1227,22 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferBySize(
return false;
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, BufV, InvalidationTraitOperations);
}
ProgramStateRef
CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) {
+ CheckerContext &C, ProgramStateRef S, SVal BufV) {
auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
const MemRegion *R) {
return isa<FieldRegion>(R);
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, BufV, InvalidationTraitOperations);
}
ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) {
+ CheckerContext &C, ProgramStateRef S, SVal BufV) {
auto InvalidationTraitOperations =
[](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
if (MemRegion::FieldRegionKind == R->getKind())
@@ -1252,12 +1252,11 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
return false;
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, BufV, InvalidationTraitOperations);
}
ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C,
ProgramStateRef S,
- const Expr *BufE,
SVal BufV) {
auto InvalidationTraitOperations =
[](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
@@ -1269,11 +1268,11 @@ ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C,
return true;
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, BufV, InvalidationTraitOperations);
}
ProgramStateRef CStringChecker::invalidateBufferAux(
- CheckerContext &C, ProgramStateRef State, const Expr *E, SVal V,
+ CheckerContext &C, ProgramStateRef State, SVal V,
llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &,
const MemRegion *)>
InvalidationTraitOperations) {
@@ -1538,8 +1537,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
// Invalidate the source (const-invalidation without const-pointer-escaping
// the address of the top-level region).
- state = invalidateSourceBuffer(C, state, Source.Expression,
- C.getSVal(Source.Expression));
+ state = invalidateSourceBuffer(C, state, C.getSVal(Source.Expression));
C.addTransition(state);
}
@@ -2245,7 +2243,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
// Invalidate the source (const-invalidation without const-pointer-escaping
// the address of the top-level region).
- state = invalidateSourceBuffer(C, state, srcExpr.Expression, srcVal);
+ state = invalidateSourceBuffer(C, state, srcVal);
// Set the C string length of the destination, if we know it.
if (IsBounded && (appendK == ConcatFnKind::none)) {
@@ -2468,8 +2466,7 @@ void CStringChecker::evalStrsep(CheckerContext &C,
// Invalidate the search string, representing the change of one delimiter
// character to NUL.
// As the replacement never overflows, do not invalidate its super region.
- State = invalidateDestinationBufferNeverOverflows(
- C, State, SearchStrPtr.Expression, Result);
+ State = invalidateDestinationBufferNeverOverflows(C, State, Result);
// Overwrite the search string pointer. The new value is either an address
// further along in the same string, or NULL if there are no more tokens.
@@ -2520,8 +2517,7 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
SVal DstVal = State->getSVal(Dst, LCtx);
// FIXME: As we do not know how many items are copied, we also invalidate the
// super region containing the target location.
- State =
- invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, Dst, DstVal);
+ State = invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, DstVal);
SValBuilder &SVB = C.getSValBuilder();
>From 1a937573aff1e24ac14cae3b6e26763fbd23273e Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 20:56:51 +0000
Subject: [PATCH 23/26] Remove unused parameters in ContainerModelling
---
clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
index 16579a691965b..a47b848f18208 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -38,7 +38,7 @@ class ContainerModeling
SVal Cont) const;
void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal,
SVal Cont) const;
- void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr,
+ void handleAssignment(CheckerContext &C, SVal Cont,
SVal OldCont = UndefinedVal()) const;
void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const;
void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const;
@@ -162,8 +162,7 @@ void ContainerModeling::checkPostCall(const CallEvent &Call,
// Overloaded 'operator=' must be a non-static member function.
const auto *InstCall = cast<CXXInstanceCall>(&Call);
if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
- handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
- Call.getArgSVal(0));
+ handleAssignment(C, InstCall->getCXXThisVal(), Call.getArgSVal(0));
return;
}
@@ -296,7 +295,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
}
void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
- const Expr *CE, SVal OldCont) const {
+ SVal OldCont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
>From df8a8434c966f933d0371b965f4bf44acbf04c46 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 21:00:25 +0000
Subject: [PATCH 24/26] Remove unused parameters in ErrnoModelling
---
clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp | 3 +--
clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h | 3 +--
.../lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp | 3 +--
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
index ee7c0adf5aa9c..3ccf55775163c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
@@ -255,8 +255,7 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
}
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
- CheckerContext &C,
- const Expr *InvalE) {
+ CheckerContext &C) {
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
if (!ErrnoR)
return State;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
index 95da8a28d3253..f568523f3e32c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
@@ -96,9 +96,8 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
/// Set errno state for the common case when a standard function indicates
/// failure only by \c errno. Sets \c ErrnoCheckState to \c MustBeChecked, and
/// invalidates the errno region (clear of previous value).
-/// \arg \c InvalE Expression that causes invalidation of \c errno.
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
- CheckerContext &C, const Expr *InvalE);
+ CheckerContext &C);
} // namespace errno_modeling
} // namespace ento
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 633877ada4742..0b31ffb7479d6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -620,8 +620,7 @@ class StdLibraryFunctionsChecker
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const override {
- return errno_modeling::setErrnoStdMustBeChecked(State, C,
- Call.getOriginExpr());
+ return errno_modeling::setErrnoStdMustBeChecked(State, C);
}
const std::string describe(CheckerContext &C) const override {
>From 1d2d5c8190d39ba9584a5b8d734cd06b9163cf16 Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 21:03:47 +0000
Subject: [PATCH 25/26] Remove unused parameters in IteratorModelling
---
.../lib/StaticAnalyzer/Checkers/IteratorModeling.cpp | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index f2161e8698f13..8e23a2ae3f564 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -119,7 +119,7 @@ class IteratorModeling
SVal Amount) const;
void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
SVal Amount) const;
- void assignToContainer(CheckerContext &C, const Expr *CE, SVal RetVal,
+ void assignToContainer(CheckerContext &C, SVal RetVal,
const MemRegion *Cont) const;
bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
@@ -224,8 +224,7 @@ void IteratorModeling::checkPostCall(const CallEvent &Call,
C.getASTContext()).getTypePtr() ==
Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) {
if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
- assignToContainer(C, OrigExpr, Call.getReturnValue(),
- Pos->getContainer());
+ assignToContainer(C, Call.getReturnValue(), Pos->getContainer());
return;
}
}
@@ -617,7 +616,7 @@ void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
State = setIteratorPosition(State, TgtVal, *NewPos);
C.addTransition(State);
} else {
- assignToContainer(C, CE, TgtVal, Pos->getContainer());
+ assignToContainer(C, TgtVal, Pos->getContainer());
}
}
@@ -661,7 +660,7 @@ void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C,
ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos);
C.addTransition(NewState);
} else {
- assignToContainer(C, Iterator, NewVal, OldPos->getContainer());
+ assignToContainer(C, NewVal, OldPos->getContainer());
}
}
@@ -681,8 +680,7 @@ void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE,
handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount);
}
-void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
- SVal RetVal,
+void IteratorModeling::assignToContainer(CheckerContext &C, SVal RetVal,
const MemRegion *Cont) const {
Cont = Cont->getMostDerivedObjectRegion();
>From 884e5bed340d19c4aac24e46cd8c67dfec6c9e4e Mon Sep 17 00:00:00 2001
From: Fangyi Zhou <me at fangyi.io>
Date: Mon, 24 Feb 2025 22:27:22 +0000
Subject: [PATCH 26/26] Fix some callsites
---
.../Checkers/CStringChecker.cpp | 31 ++++++++++---------
.../StaticAnalyzer/Checkers/MallocChecker.cpp | 4 +--
.../Checkers/SmartPtrModeling.cpp | 4 +--
.../Checkers/StdLibraryFunctionsChecker.cpp | 2 +-
.../StaticAnalyzer/Checkers/StreamChecker.cpp | 2 +-
5 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 3625ad80dff4f..c946559ffa0db 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -1514,7 +1514,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
// conjure a return value for later.
if (lastElement.isUnknown())
lastElement = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), C.getCFGElementRef(), LCtx,
+ nullptr, Call.getOriginExpr(), Call.getCFGElementRef(), LCtx,
C.blockCount());
// The byte after the last byte copied is the return value.
@@ -1664,9 +1664,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
if (State) {
// The return value is the comparison result, which we don't know.
- SVal CmpV =
- Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
- C.getCFGElementRef(), LCtx, C.blockCount());
+ SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ Call.getCFGElementRef(), LCtx,
+ C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
C.addTransition(State);
}
@@ -1770,7 +1770,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), C.getCFGElementRef(), LCtx,
+ nullptr, Call.getOriginExpr(), Call.getCFGElementRef(), LCtx,
C.blockCount());
NonLoc resultNL = result.castAs<NonLoc>();
@@ -1795,7 +1795,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), C.getCFGElementRef(), LCtx,
+ nullptr, Call.getOriginExpr(), Call.getCFGElementRef(), LCtx,
C.blockCount());
}
}
@@ -2264,7 +2264,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
// overflow, we still need a result. Conjure a return value.
if (ReturnEnd && Result.isUnknown()) {
Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
- C.getCFGElementRef(), LCtx,
+ Call.getCFGElementRef(), LCtx,
C.blockCount());
}
}
@@ -2364,9 +2364,9 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
const StringLiteral *RightStrLiteral =
getCStringLiteral(C, state, Right.Expression, RightVal);
bool canComputeResult = false;
- SVal resultVal =
- svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
- C.getCFGElementRef(), LCtx, C.blockCount());
+ SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ Call.getCFGElementRef(), LCtx,
+ C.blockCount());
if (LeftStrLiteral && RightStrLiteral) {
StringRef LeftStrRef = LeftStrLiteral->getString();
@@ -2472,14 +2472,15 @@ void CStringChecker::evalStrsep(CheckerContext &C,
// further along in the same string, or NULL if there are no more tokens.
State =
State->bindLoc(*SearchStrLoc,
- SVB.conjureSymbolVal(getTag(), C.getCFGElementRef(),
+ SVB.conjureSymbolVal(getTag(), Call.getCFGElementRef(),
LCtx, CharPtrTy, C.blockCount()),
LCtx);
} else {
assert(SearchStrVal.isUnknown());
// Conjure a symbolic value. It's the best we can do.
- Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(),
- C.getCFGElementRef(), LCtx, C.blockCount());
+ Result =
+ SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ Call.getCFGElementRef(), LCtx, C.blockCount());
}
// Set the return value, and finish.
@@ -2522,8 +2523,8 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
SValBuilder &SVB = C.getSValBuilder();
SVal ResultVal =
- SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), C.getCFGElementRef(),
- LCtx, C.blockCount());
+ SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(),
+ Call.getCFGElementRef(), LCtx, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
C.addTransition(State);
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 857974be0c582..4b8da0562b4d3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1835,7 +1835,7 @@ ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
DefinedSVal RetVal =
isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
- : SVB.getConjuredHeapSymbolVal(C.getCFGElementRef(), LCtx,
+ : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
CE->getType(), Count);
return State->BindExpr(CE, C.getLocationContext(), RetVal);
}
@@ -2306,7 +2306,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
// Assume that after memory is freed, it contains unknown values. This
// conforts languages standards, since reading from freed memory is considered
// UB and may result in arbitrary value.
- State = State->invalidateRegions({location}, C.getCFGElementRef(),
+ State = State->invalidateRegions({location}, Call.getCFGElementRef(),
C.blockCount(), C.getLocationContext(),
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr);
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index fa4cf3e2ceeba..feb67fc07c039 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -306,7 +306,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
return false;
const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal(
- C.getCFGElementRef(), C.getLocationContext(),
+ Call.getCFGElementRef(), C.getLocationContext(),
getPointerTypeFromTemplateArg(Call, C), C.blockCount());
const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
@@ -530,7 +530,7 @@ bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call,
if (!StreamThisRegion)
return false;
State =
- State->invalidateRegions({StreamThisRegion}, C.getCFGElementRef(),
+ State->invalidateRegions({StreamThisRegion}, Call.getCFGElementRef(),
C.blockCount(), C.getLocationContext(), false);
State =
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal);
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 0b31ffb7479d6..8ec0e340ed15c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -585,7 +585,7 @@ class StdLibraryFunctionsChecker
CheckerContext &C) const override {
SValBuilder &SVB = C.getSValBuilder();
NonLoc ErrnoSVal =
- SVB.conjureSymbolVal(&Tag, C.getCFGElementRef(),
+ SVB.conjureSymbolVal(&Tag, Call.getCFGElementRef(),
C.getLocationContext(), C.getASTContext().IntTy,
C.blockCount())
.castAs<NonLoc>();
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 2a890b96fa0e1..9a53b003bc7de 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -868,7 +868,7 @@ static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C,
ArrayRef<unsigned int> EscapingArgs) {
auto GetArgSVal = [&Call](int Idx) { return Call.getArgSVal(Idx); };
auto EscapingVals = to_vector(map_range(EscapingArgs, GetArgSVal));
- State = State->invalidateRegions(EscapingVals, C.getCFGElementRef(),
+ State = State->invalidateRegions(EscapingVals, Call.getCFGElementRef(),
C.blockCount(), C.getLocationContext(),
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr);
More information about the cfe-commits
mailing list