[clang] [Clang] [analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
https://github.com/fangyi-zhou created https://github.com/llvm/llvm-project/pull/128251 Closes #57270. This PR changes the `Stmt *` field in `SymbolConjured` with `CFGBlock::ConstCFGElementRef`. The motivation is that, when conjuring a symbol, there might not always be a statement available, causing information to be lost for conjured symbols, whereas the CFGElementRef can always be provided at the callsite. Following the idea, this PR changes callsites of functions to create conjured symbols, and replaces them with appropriate `CFGElementRef`s. >From 97c4e0e39ba5e9486e893691b40e78fe3d8548b0 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Fri, 21 Feb 2025 20:54:08 + Subject: [PATCH 1/3] 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 getConjuredHea
[clang] [Clang] [analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -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, fangyi-zhou wrote: Q: Here `Call` is possibly null, how should I get a ref here? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -171,20 +172,27 @@ class SValBuilder { // Forwarding methods to SymbolManager. - 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 CFGBlock::ConstCFGElementRef ElemRef, +const LocationContext *LCtx, QualType type, unsigned visitCount, +const void *symbolTag = nullptr) { +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, fangyi-zhou wrote: Will remove these commented out lines before marking this PR as ready. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -113,19 +120,21 @@ 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); fangyi-zhou wrote: Q: Do I need to add `ElemRef` to the profile? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -867,18 +868,18 @@ 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, fangyi-zhou wrote: Fixed in new commits. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -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) { fangyi-zhou wrote: Fixed in new commits. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -111,8 +111,13 @@ class SValExplainer : public FullSValVisitor { } 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); fangyi-zhou wrote: `printStmt()` delegates to `Stmt::printPretty()`, but I don't immediately see any equivalent for `CFGElementRef`. The slightly annoying thing about `dumpToStream` for `CFGElementRef` is that it has an newline character in the end... https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
https://github.com/fangyi-zhou ready_for_review https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
fangyi-zhou wrote: I've made some more progress, the crash goes away, there are still some review comments that I need to address, which I'll try to complete later. ``` /home/fangyi/playground/bug.cc:21:5: warning: value derived from (symbol of type 'int' conjured at statement '->~S() (Implicit destructor) ') for global variable 'S::a' [debug.ExprInspection] 21 | clang_analyzer_explain(S::a); | ^~~~ 1 warning generated. ``` https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -111,8 +111,13 @@ class SValExplainer : public FullSValVisitor { } 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); fangyi-zhou wrote: Q: Do we have a way to pretty print a CFGElementRef instead of `dumpToStream`? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -151,72 +151,63 @@ 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, fangyi-zhou wrote: Note to self: This should probably be added back in some shape or form since it has some different behaviour when handling expressions with a provided type --- which means it's not entirely same to calling `conjureSymbolVal(SymbolTag, Ex, LCtx, Ex->getType(), Count)`. Probably need to revisit all callsites and check. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
https://github.com/fangyi-zhou edited https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -494,7 +494,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())); +C.getCFGElementRef(), LCtx, C.getASTContext().BoolTy, C.blockCount())); State = State->BindExpr(CE, LCtx, RetVal); fangyi-zhou wrote: Used here. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -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, fangyi-zhou wrote: Not any more, will remove. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -171,19 +172,11 @@ class SValBuilder { // Forwarding methods to SymbolManager. - 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); + const SymbolConjured * + conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef, fangyi-zhou wrote: We can try to downcast the `ElemRef` for a statement, and try to downcast as an expression to obtain the type in those cases. I guess it would work in the callsites in the deleted overload if the `ElemRef` are statements. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -171,19 +172,11 @@ class SValBuilder { // Forwarding methods to SymbolManager. - 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); + const SymbolConjured * + conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef, fangyi-zhou wrote: The type needs to come from the expression, which we don't pass in as an argument any more. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -198,32 +191,24 @@ 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); + 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); + 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, fangyi-zhou wrote: Same as above. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -533,18 +538,12 @@ class SymbolManager { template const SymExprT *acquire(Args &&...args); - const SymbolConjured *conjureSymbol(const Stmt *E, - const LocationContext *LCtx, QualType T, - unsigned VisitCount, - const void *SymbolTag = nullptr) { -return acquire(E, LCtx, T, VisitCount, SymbolTag); - } + const SymbolConjured * + conjureSymbol(const CFGBlock::ConstCFGElementRef ElemRef, fangyi-zhou wrote: Same as above. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -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.getOriginExpr(), C.getCFGElementRef(), LCtx, fangyi-zhou wrote: I don't know what's the correct one to pass and don't have a way to check reliably since I don't understand the static analysis code. I don't understand your intention in this comment, do you mean I should pass the CFGElementRef to the Call or not? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -198,32 +191,24 @@ 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); + DefinedOrUnknownSVal + conjureSymbolVal(const void *symbolTag, const Expr *expr, + const CFGBlock::ConstCFGElementRef elemRef, fangyi-zhou wrote: If you look at the implementation code, there's some special treatment wrt the type of the expression https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -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, fangyi-zhou wrote: Are you referring to this instance that I should pass the refernece to the statement instead of the call? I think I misunderstood this comment so I changed the references to not use the one from the call in all places. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -151,10 +151,10 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion *region) { return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, fangyi-zhou wrote: This overload would have been removed, but its behaviour is not entirely the same as obtaining the type from the expression directly. (See the check for `isGLValue`). Without complicating the refactor in this PR I decided to leave it as is, and add a new parameter for the CFG Element Ref https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -166,57 +166,47 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, if (Ex->isGLValue()) T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType); - return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count); + return conjureSymbolVal(SymbolTag, elemRef, 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)); 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)); return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E, fangyi-zhou wrote: This overload is removed since it's not possible to retrieve the type from the CFGElementRef. If there's a way to obtain it please let me know so I can add it back. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -695,6 +695,21 @@ class CFGBlock { void dump() const { dumpToStream(llvm::errs()); } + +void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Parent); + ID.AddInteger(Index); +} + +int64_t getID() const { fangyi-zhou wrote: Any suggestion for replacement? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
fangyi-zhou wrote: May I get a re-review for the changes please? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou ready_for_review https://github.com/llvm/llvm-project/pull/136041 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou created https://github.com/llvm/llvm-project/pull/136041 As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. >From 13d4ea6b0fb61ad27f596edbdf7daf20921f6989 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Wed, 16 Apr 2025 22:51:36 +0100 Subject: [PATCH] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. --- .../Checkers/DynamicTypePropagation.cpp | 10 ++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 11 +++ clang/test/Analysis/PR135665.cpp| 17 + 3 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 clang/test/Analysis/PR135665.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a0bf776b11f53..6fad0601e87ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -379,10 +379,12 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // aggregates, and in such case no top-frame constructor will be called. // Figure out if we need to do anything in this case. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) available in this -// callback, ideally as part of CallEvent. -if (isa_and_nonnull( -LCtx->getParentMap().getParent(Ctor->getOriginExpr( +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// available in this callback, ideally as part of CallEvent. +const Stmt *Parent = +LCtx->getParentMap().getParent(Ctor->getOriginExpr()); +if (isa_and_nonnull(Parent) || +isa_and_nonnull(Parent)) return; recordFixedType(Target, cast(LCtx->getDecl()), C); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 7e878f922a939..914859861b948 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -644,9 +644,11 @@ void ExprEngine::handleConstructor(const Expr *E, // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) passed down from CFG or -// otherwise always available during construction. -if (isa_and_nonnull(LCtx->getParentMap().getParent(E))) { +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// passed down from CFG or otherwise always available during construction. +if (isa_and_nonnull(LCtx->getParentMap().getParent(E)) || +isa_and_nonnull( +LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; @@ -1017,7 +1019,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // values are properly placed inside the required region, however if an // initializer list is used, this doesn't happen automatically. auto *Init = CNE->getInitializer(); - bool isInitList = isa_and_nonnull(Init); + bool isInitList = isa_and_nonnull(Init) || +isa_and_nonnull(Init); QualType ObjTy = isInitList ? Init->getType() : CNE->getType()->getPointeeType(); diff --git a/clang/test/Analysis/PR135665.cpp b/clang/test/Analysis/PR135665.cpp new file mode 100644 index 0..07848d9a590f5 --- /dev/null +++ b/clang/test/Analysis/PR135665.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s + +template +struct overload : public F... +{ + using F::operator()...; +}; + +template +overload(F&&...) -> overload; + +int main() +{ + const auto l = overload([](const int* i) {}); + + return 0; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
fangyi-zhou wrote: Sorry I've been a bit busy with other things, just had some time to address the review comments. Please let me know if anything else needs changing https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/136041 >From 6379f403e0967b820f9385581f9d23dd18297831 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Wed, 16 Apr 2025 23:52:39 +0100 Subject: [PATCH] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. --- clang/docs/ReleaseNotes.rst | 22 --- .../Checkers/DynamicTypePropagation.cpp | 6 ++--- .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 10 + clang/test/Analysis/PR135665.cpp | 19 4 files changed, 32 insertions(+), 25 deletions(-) create mode 100644 clang/test/Analysis/PR135665.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c75d83a6d1a7a..88259fbb8278d 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -219,12 +219,6 @@ Modified Compiler Flags - `-Wpadded` option implemented for the `x86_64-windows-msvc` target. Fixes #61702 -- The ``-mexecute-only`` and ``-mpure-code`` flags are now accepted for AArch64 targets. (#GH125688) - -- The ``-Og`` optimization flag now sets ``-fextend-variable-liveness``, - reducing performance slightly while reducing the number of optimized-out - variables. - Removed Compiler Flags - @@ -432,9 +426,6 @@ Bug Fixes in This Version using C++23 "deducing this" did not have a diagnostic location (#GH135522) - Fixed a crash when a ``friend`` function is redefined as deleted. (#GH135506) -- Fixed a crash when ``#embed`` appears as a part of a failed constant - evaluation. The crashes were happening during diagnostics emission due to - unimplemented statement printer. (#GH132641) Bug Fixes to Compiler Builtins ^^ @@ -477,11 +468,9 @@ Bug Fixes to C++ Support by template argument deduction. - Clang is now better at instantiating the function definition after its use inside of a constexpr lambda. (#GH125747) -- Fixed a local class member function instantiation bug inside dependent lambdas. (#GH59734), (#GH132208) - Clang no longer crashes when trying to unify the types of arrays with certain differences in qualifiers (this could happen during template argument deduction or when building a ternary operator). (#GH97005) -- Fixed type alias CTAD issues involving default template arguments. (#GH134471) - The initialization kind of elements of structured bindings direct-list-initialized from an array is corrected to direct-initialization. - Clang no longer crashes when a coroutine is declared ``[[noreturn]]``. (#GH127327) @@ -497,10 +486,6 @@ Bug Fixes to C++ Support - Fixes matching of nested template template parameters. (#GH130362) - Correctly diagnoses template template paramters which have a pack parameter not in the last position. -- Disallow overloading on struct vs class on dependent types, which is IFNDR, as - this makes the problem diagnosable. -- Improved preservation of the presence or abscence of typename specifier when - printing types in diagnostics. - Clang now correctly parses ``if constexpr`` expressions in immediate function context. (#GH123524) - Fixed an assertion failure affecting code that uses C++23 "deducing this". (#GH130272) - Clang now properly instantiates destructors for initialized members within non-delegating constructors. (#GH93251) @@ -575,9 +560,6 @@ Arm and AArch64 Support - Support for __ptrauth type qualifier has been added. -- For AArch64, added support for generating executable-only code sections by using the - ``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688) - Android Support ^^^ @@ -667,6 +649,10 @@ Code Completion Static Analyzer --- +- Fixed a crash when C++20 parenthesized initializer lists are used. This issue + was causing a crash in clang-tidy. (#GH136041) + +- Fixed a crash when C++20 parenthesized initializer lists are used. (#GH136041) New features diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a0bf776b11f53..e58329817d7cd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -379,9 +379,9 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // aggregates, and in such case no top-frame constructor will be called. // Figure out if we need to do anything in this case. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) available in this -// callback, ideally as part
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/136041 >From 5dc9d55eb04d94c01dba0364b51a509f975e542a Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Thu, 17 Apr 2025 23:02:37 +0100 Subject: [PATCH] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. --- clang/docs/ReleaseNotes.rst | 2 ++ .../Checkers/DynamicTypePropagation.cpp | 6 +++--- .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 10 ++ clang/test/Analysis/PR135665.cpp | 19 +++ 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 clang/test/Analysis/PR135665.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c75d83a6d1a7a..85e095e6b1acc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -667,6 +667,8 @@ Code Completion Static Analyzer --- +- Fixed a crash when C++20 parenthesized initializer lists are used. This issue + was causing a crash in clang-tidy. (#GH136041) New features diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a0bf776b11f53..e58329817d7cd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -379,9 +379,9 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // aggregates, and in such case no top-frame constructor will be called. // Figure out if we need to do anything in this case. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) available in this -// callback, ideally as part of CallEvent. -if (isa_and_nonnull( +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// available in this callback, ideally as part of CallEvent. +if (isa_and_nonnull( LCtx->getParentMap().getParent(Ctor->getOriginExpr( return; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 7e878f922a939..92ce3fa2225c8 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -644,9 +644,10 @@ void ExprEngine::handleConstructor(const Expr *E, // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) passed down from CFG or -// otherwise always available during construction. -if (isa_and_nonnull(LCtx->getParentMap().getParent(E))) { +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// passed down from CFG or otherwise always available during construction. +if (isa_and_nonnull( +LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; @@ -1017,7 +1018,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // values are properly placed inside the required region, however if an // initializer list is used, this doesn't happen automatically. auto *Init = CNE->getInitializer(); - bool isInitList = isa_and_nonnull(Init); + bool isInitList = + isa_and_nonnull(Init); QualType ObjTy = isInitList ? Init->getType() : CNE->getType()->getPointeeType(); diff --git a/clang/test/Analysis/PR135665.cpp b/clang/test/Analysis/PR135665.cpp new file mode 100644 index 0..124b8c9b97b04 --- /dev/null +++ b/clang/test/Analysis/PR135665.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_analyze_cc1 -std=c++20 -analyzer-checker=core -verify %s + +// expected-no-diagnostics + +template +struct overload : public F... +{ + using F::operator()...; +}; + +template +overload(F&&...) -> overload; + +int main() +{ + const auto l = overload([](const int* i) {}); + + return 0; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/136041 >From a0b769ee35df18418ed410e30ac6cdde9024a4f1 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Wed, 16 Apr 2025 23:52:39 +0100 Subject: [PATCH 1/4] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. --- .../Checkers/DynamicTypePropagation.cpp | 10 ++ .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 11 +++ clang/test/Analysis/PR135665.cpp | 19 +++ 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 clang/test/Analysis/PR135665.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a0bf776b11f53..6fad0601e87ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -379,10 +379,12 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // aggregates, and in such case no top-frame constructor will be called. // Figure out if we need to do anything in this case. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) available in this -// callback, ideally as part of CallEvent. -if (isa_and_nonnull( -LCtx->getParentMap().getParent(Ctor->getOriginExpr( +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// available in this callback, ideally as part of CallEvent. +const Stmt *Parent = +LCtx->getParentMap().getParent(Ctor->getOriginExpr()); +if (isa_and_nonnull(Parent) || +isa_and_nonnull(Parent)) return; recordFixedType(Target, cast(LCtx->getDecl()), C); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 7e878f922a939..914859861b948 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -644,9 +644,11 @@ void ExprEngine::handleConstructor(const Expr *E, // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) passed down from CFG or -// otherwise always available during construction. -if (isa_and_nonnull(LCtx->getParentMap().getParent(E))) { +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// passed down from CFG or otherwise always available during construction. +if (isa_and_nonnull(LCtx->getParentMap().getParent(E)) || +isa_and_nonnull( +LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; @@ -1017,7 +1019,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // values are properly placed inside the required region, however if an // initializer list is used, this doesn't happen automatically. auto *Init = CNE->getInitializer(); - bool isInitList = isa_and_nonnull(Init); + bool isInitList = isa_and_nonnull(Init) || +isa_and_nonnull(Init); QualType ObjTy = isInitList ? Init->getType() : CNE->getType()->getPointeeType(); diff --git a/clang/test/Analysis/PR135665.cpp b/clang/test/Analysis/PR135665.cpp new file mode 100644 index 0..124b8c9b97b04 --- /dev/null +++ b/clang/test/Analysis/PR135665.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_analyze_cc1 -std=c++20 -analyzer-checker=core -verify %s + +// expected-no-diagnostics + +template +struct overload : public F... +{ + using F::operator()...; +}; + +template +overload(F&&...) -> overload; + +int main() +{ + const auto l = overload([](const int* i) {}); + + return 0; +} >From 8b915918692b49b9eb4fb06bd5d9ee863354 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Thu, 17 Apr 2025 17:43:07 +0100 Subject: [PATCH 2/4] Fix isa_and_nonnull calls --- .../lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp | 6 ++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 6fad0601e87ca..e58329817d7cd 100644 --- a/clang/lib/StaticAnalyzer/Che
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
fangyi-zhou wrote: Sorry I didn't notice, will fix. https://github.com/llvm/llvm-project/pull/136041 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/136041 >From a0b769ee35df18418ed410e30ac6cdde9024a4f1 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Wed, 16 Apr 2025 23:52:39 +0100 Subject: [PATCH] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. --- .../Checkers/DynamicTypePropagation.cpp | 10 ++ .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 11 +++ clang/test/Analysis/PR135665.cpp | 19 +++ 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 clang/test/Analysis/PR135665.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a0bf776b11f53..6fad0601e87ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -379,10 +379,12 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // aggregates, and in such case no top-frame constructor will be called. // Figure out if we need to do anything in this case. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) available in this -// callback, ideally as part of CallEvent. -if (isa_and_nonnull( -LCtx->getParentMap().getParent(Ctor->getOriginExpr( +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// available in this callback, ideally as part of CallEvent. +const Stmt *Parent = +LCtx->getParentMap().getParent(Ctor->getOriginExpr()); +if (isa_and_nonnull(Parent) || +isa_and_nonnull(Parent)) return; recordFixedType(Target, cast(LCtx->getDecl()), C); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 7e878f922a939..914859861b948 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -644,9 +644,11 @@ void ExprEngine::handleConstructor(const Expr *E, // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) passed down from CFG or -// otherwise always available during construction. -if (isa_and_nonnull(LCtx->getParentMap().getParent(E))) { +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// passed down from CFG or otherwise always available during construction. +if (isa_and_nonnull(LCtx->getParentMap().getParent(E)) || +isa_and_nonnull( +LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; @@ -1017,7 +1019,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // values are properly placed inside the required region, however if an // initializer list is used, this doesn't happen automatically. auto *Init = CNE->getInitializer(); - bool isInitList = isa_and_nonnull(Init); + bool isInitList = isa_and_nonnull(Init) || +isa_and_nonnull(Init); QualType ObjTy = isInitList ? Init->getType() : CNE->getType()->getPointeeType(); diff --git a/clang/test/Analysis/PR135665.cpp b/clang/test/Analysis/PR135665.cpp new file mode 100644 index 0..124b8c9b97b04 --- /dev/null +++ b/clang/test/Analysis/PR135665.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_analyze_cc1 -std=c++20 -analyzer-checker=core -verify %s + +// expected-no-diagnostics + +template +struct overload : public F... +{ + using F::operator()...; +}; + +template +overload(F&&...) -> overload; + +int main() +{ + const auto l = overload([](const int* i) {}); + + return 0; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/136041 >From a0b769ee35df18418ed410e30ac6cdde9024a4f1 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Wed, 16 Apr 2025 23:52:39 +0100 Subject: [PATCH 1/3] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. --- .../Checkers/DynamicTypePropagation.cpp | 10 ++ .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 11 +++ clang/test/Analysis/PR135665.cpp | 19 +++ 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 clang/test/Analysis/PR135665.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a0bf776b11f53..6fad0601e87ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -379,10 +379,12 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // aggregates, and in such case no top-frame constructor will be called. // Figure out if we need to do anything in this case. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) available in this -// callback, ideally as part of CallEvent. -if (isa_and_nonnull( -LCtx->getParentMap().getParent(Ctor->getOriginExpr( +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// available in this callback, ideally as part of CallEvent. +const Stmt *Parent = +LCtx->getParentMap().getParent(Ctor->getOriginExpr()); +if (isa_and_nonnull(Parent) || +isa_and_nonnull(Parent)) return; recordFixedType(Target, cast(LCtx->getDecl()), C); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 7e878f922a939..914859861b948 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -644,9 +644,11 @@ void ExprEngine::handleConstructor(const Expr *E, // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) passed down from CFG or -// otherwise always available during construction. -if (isa_and_nonnull(LCtx->getParentMap().getParent(E))) { +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// passed down from CFG or otherwise always available during construction. +if (isa_and_nonnull(LCtx->getParentMap().getParent(E)) || +isa_and_nonnull( +LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; @@ -1017,7 +1019,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // values are properly placed inside the required region, however if an // initializer list is used, this doesn't happen automatically. auto *Init = CNE->getInitializer(); - bool isInitList = isa_and_nonnull(Init); + bool isInitList = isa_and_nonnull(Init) || +isa_and_nonnull(Init); QualType ObjTy = isInitList ? Init->getType() : CNE->getType()->getPointeeType(); diff --git a/clang/test/Analysis/PR135665.cpp b/clang/test/Analysis/PR135665.cpp new file mode 100644 index 0..124b8c9b97b04 --- /dev/null +++ b/clang/test/Analysis/PR135665.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_analyze_cc1 -std=c++20 -analyzer-checker=core -verify %s + +// expected-no-diagnostics + +template +struct overload : public F... +{ + using F::operator()...; +}; + +template +overload(F&&...) -> overload; + +int main() +{ + const auto l = overload([](const int* i) {}); + + return 0; +} >From 8b915918692b49b9eb4fb06bd5d9ee863354 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Thu, 17 Apr 2025 17:43:07 +0100 Subject: [PATCH 2/3] Fix isa_and_nonnull calls --- .../lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp | 6 ++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 6fad0601e87ca..e58329817d7cd 100644 --- a/clang/lib/StaticAnalyzer/Che
[clang] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr (PR #136041)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/136041 >From a0b769ee35df18418ed410e30ac6cdde9024a4f1 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Wed, 16 Apr 2025 23:52:39 +0100 Subject: [PATCH 1/4] [clang][analyzer] Handle CXXParenInitListExpr alongside InitListExpr As reported in #135665, C++20 parenthesis initializer list expressions are not handled correctly and were causing crashes. This commit attempts to fix the issue by handing parenthesis initializer lists along side existing initializer lists. --- .../Checkers/DynamicTypePropagation.cpp | 10 ++ .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 11 +++ clang/test/Analysis/PR135665.cpp | 19 +++ 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 clang/test/Analysis/PR135665.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index a0bf776b11f53..6fad0601e87ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -379,10 +379,12 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // aggregates, and in such case no top-frame constructor will be called. // Figure out if we need to do anything in this case. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) available in this -// callback, ideally as part of CallEvent. -if (isa_and_nonnull( -LCtx->getParentMap().getParent(Ctor->getOriginExpr( +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// available in this callback, ideally as part of CallEvent. +const Stmt *Parent = +LCtx->getParentMap().getParent(Ctor->getOriginExpr()); +if (isa_and_nonnull(Parent) || +isa_and_nonnull(Parent)) return; recordFixedType(Target, cast(LCtx->getDecl()), C); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 7e878f922a939..914859861b948 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -644,9 +644,11 @@ void ExprEngine::handleConstructor(const Expr *E, // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // FIXME: Instead of relying on the ParentMap, we should have the -// trigger-statement (InitListExpr in this case) passed down from CFG or -// otherwise always available during construction. -if (isa_and_nonnull(LCtx->getParentMap().getParent(E))) { +// trigger-statement (InitListExpr or CXXParenListInitExpr in this case) +// passed down from CFG or otherwise always available during construction. +if (isa_and_nonnull(LCtx->getParentMap().getParent(E)) || +isa_and_nonnull( +LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; @@ -1017,7 +1019,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // values are properly placed inside the required region, however if an // initializer list is used, this doesn't happen automatically. auto *Init = CNE->getInitializer(); - bool isInitList = isa_and_nonnull(Init); + bool isInitList = isa_and_nonnull(Init) || +isa_and_nonnull(Init); QualType ObjTy = isInitList ? Init->getType() : CNE->getType()->getPointeeType(); diff --git a/clang/test/Analysis/PR135665.cpp b/clang/test/Analysis/PR135665.cpp new file mode 100644 index 0..124b8c9b97b04 --- /dev/null +++ b/clang/test/Analysis/PR135665.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_analyze_cc1 -std=c++20 -analyzer-checker=core -verify %s + +// expected-no-diagnostics + +template +struct overload : public F... +{ + using F::operator()...; +}; + +template +overload(F&&...) -> overload; + +int main() +{ + const auto l = overload([](const int* i) {}); + + return 0; +} >From 8b915918692b49b9eb4fb06bd5d9ee863354 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Thu, 17 Apr 2025 17:43:07 +0100 Subject: [PATCH 2/4] Fix isa_and_nonnull calls --- .../lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp | 6 ++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 6fad0601e87ca..e58329817d7cd 100644 --- a/clang/lib/StaticAnalyzer/Che
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -93,9 +76,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, fangyi-zhou wrote: I don't have a good answer to these questions... Any tips? I don't see any immediate ways to extract the required information https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -645,6 +645,7 @@ struct StreamOperationEvaluator { SymbolRef StreamSym = nullptr; const StreamState *SS = nullptr; const CallExpr *CE = nullptr; + std::optional ElemRef; fangyi-zhou wrote: I'm not entirely sure whether I get your point correctly. This value needs to be stored when `Init` is called, and used in other calls (e.g. `bindReturnValue`). The reason why this is declared as an optional is that there is no default constructor for `ConstCFGElementRef`, so I used an optional to give an absent value (I guess it could have been a pointer like other ones) https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
https://github.com/fangyi-zhou ready_for_review https://github.com/llvm/llvm-project/pull/137182 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
https://github.com/fangyi-zhou created https://github.com/llvm/llvm-project/pull/137182 Per suggestion in https://github.com/llvm/llvm-project/pull/128251#discussion_r2055916229, adding a new helper function in `SValBuilder` to conjure a symbol when given a `CallEvent`. Tested manually (with assertions) that the `LocationContext *` obtained from the `CallEvent` are identical to those passed in the original argument. >From 79e5875e75d46edcf15c5df536ac8f1d93e13a16 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Thu, 24 Apr 2025 15:12:12 +0100 Subject: [PATCH] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events Per suggestion in https://github.com/llvm/llvm-project/pull/128251#discussion_r2055916229, adding a new helper function in `SValBuilder` to conjure a symbol when given a `CallEvent`. Tested manually (with assertions) that the `LocationContext *` obtained from the `CallEvent` are identical to those passed in the original argument. --- .../Core/PathSensitive/SValBuilder.h | 8 - .../Checkers/CStringChecker.cpp | 32 +++ .../Checkers/ErrnoTesterChecker.cpp | 3 +- .../RetainCountChecker/RetainCountChecker.cpp | 3 +- .../Checkers/SmartPtrModeling.cpp | 2 +- .../Checkers/StdLibraryFunctionsChecker.cpp | 10 +++--- .../Checkers/cert/InvalidPtrChecker.cpp | 4 +-- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 25 +-- 8 files changed, 42 insertions(+), 45 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 54430d426a82a..3f3e6bdb9ff3d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -46,10 +46,10 @@ class Stmt; namespace ento { +class CallEvent; class ConditionTruthVal; class ProgramStateManager; class StoreRef; - class SValBuilder { virtual void anchor(); @@ -209,6 +209,12 @@ class SValBuilder { const LocationContext *LCtx, QualType type, unsigned visitCount); + DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, QualType type, +unsigned visitCount, +const void *symbolTag = nullptr); + DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, +unsigned visitCount, +const void *symbolTag = nullptr); /// Conjure a symbol representing heap allocated memory region. /// diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 39dcaf02dbe25..9d3eda8f7f982 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1514,8 +1514,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // If we don't know how much we copied, we can at least // conjure a return value for later. if (lastElement.isUnknown()) -lastElement = C.getSValBuilder().conjureSymbolVal( -nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); +lastElement = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); // The byte after the last byte copied is the return value. state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement); @@ -1665,8 +1664,7 @@ 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(Call, C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV); C.addTransition(State); } @@ -1769,8 +1767,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // no guarantee the full string length will actually be returned. // 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()); + result = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); NonLoc resultNL = result.castAs(); if (strLengthNL) { @@ -1793,8 +1790,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // If we don't know the length of the string, conjure a return // value, so it can be used in constraints, at least. if (
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -2463,19 +2473,19 @@ void CStringChecker::evalStrsep(CheckerContext &C, // character to NUL. // As the replacement never overflows, do not invalidate its super region. State = invalidateDestinationBufferNeverOverflows( -C, State, SearchStrPtr.Expression, Result); +C, State, Call.getCFGElementRef(), 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. 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, +Result = SVB.conjureSymbolVal(nullptr, Call.getCFGElementRef(), LCtx, C.blockCount()); } fangyi-zhou wrote: I've created a new pull request for this refactor https://github.com/llvm/llvm-project/pull/137182 Depending on which PR gets merged first I'll rebase one upon another. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/137182 >From 79e5875e75d46edcf15c5df536ac8f1d93e13a16 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Thu, 24 Apr 2025 15:12:12 +0100 Subject: [PATCH 1/2] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events Per suggestion in https://github.com/llvm/llvm-project/pull/128251#discussion_r2055916229, adding a new helper function in `SValBuilder` to conjure a symbol when given a `CallEvent`. Tested manually (with assertions) that the `LocationContext *` obtained from the `CallEvent` are identical to those passed in the original argument. --- .../Core/PathSensitive/SValBuilder.h | 8 - .../Checkers/CStringChecker.cpp | 32 +++ .../Checkers/ErrnoTesterChecker.cpp | 3 +- .../RetainCountChecker/RetainCountChecker.cpp | 3 +- .../Checkers/SmartPtrModeling.cpp | 2 +- .../Checkers/StdLibraryFunctionsChecker.cpp | 10 +++--- .../Checkers/cert/InvalidPtrChecker.cpp | 4 +-- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 25 +-- 8 files changed, 42 insertions(+), 45 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 54430d426a82a..3f3e6bdb9ff3d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -46,10 +46,10 @@ class Stmt; namespace ento { +class CallEvent; class ConditionTruthVal; class ProgramStateManager; class StoreRef; - class SValBuilder { virtual void anchor(); @@ -209,6 +209,12 @@ class SValBuilder { const LocationContext *LCtx, QualType type, unsigned visitCount); + DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, QualType type, +unsigned visitCount, +const void *symbolTag = nullptr); + DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, +unsigned visitCount, +const void *symbolTag = nullptr); /// Conjure a symbol representing heap allocated memory region. /// diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 39dcaf02dbe25..9d3eda8f7f982 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1514,8 +1514,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // If we don't know how much we copied, we can at least // conjure a return value for later. if (lastElement.isUnknown()) -lastElement = C.getSValBuilder().conjureSymbolVal( -nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); +lastElement = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); // The byte after the last byte copied is the return value. state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement); @@ -1665,8 +1664,7 @@ 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(Call, C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV); C.addTransition(State); } @@ -1769,8 +1767,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // no guarantee the full string length will actually be returned. // 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()); + result = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); NonLoc resultNL = result.castAs(); if (strLengthNL) { @@ -1793,8 +1790,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // If we don't know the length of the string, conjure a return // value, so it can be used in constraints, at least. if (result.isUnknown()) { - result = C.getSValBuilder().conjureSymbolVal( - nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); + result = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); } } @@ -2261,8 +2257,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -2556,10 +2556,19 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt(); if (!isa_and_nonnull(Term)) return; + +// FIXME: fangyi-zhou wrote: Fair enough, I will remove the assertion but leave this FIXME here for future reference. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
fangyi-zhou wrote: Thanks for the review. I might have missed some comments since I was away from this pull request for quite a while and I probably forgot. I'll have another revision. https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -114,7 +128,8 @@ class SValExplainer : public FullSValVisitor { std::string VisitSymbolConjured(const SymbolConjured *S) { return "symbol of type '" + S->getType().getAsString() + - "' conjured at statement '" + printStmt(S->getStmt()) + "'"; + "' conjured at statement '" + fangyi-zhou wrote: My intention was to keep this is as for now to avoid making visible changes (i.e. the emitted diagnostics). If it's desirable to change this to a CFG Element, I can make the required change (although that would include changing some test cases) https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
fangyi-zhou wrote: Could you please merge this pull request first, now that the other one got reverted? https://github.com/llvm/llvm-project/pull/137182 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
@@ -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, InnerPointerType, C.blockCount()); fangyi-zhou wrote: For example, this inner pointer type is sometimes different from the call result type. https://github.com/llvm/llvm-project/pull/137182 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
@@ -584,11 +584,9 @@ class StdLibraryFunctionsChecker const Summary &Summary, CheckerContext &C) const override { SValBuilder &SVB = C.getSValBuilder(); - NonLoc ErrnoSVal = - SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(), - C.getLocationContext(), C.getASTContext().IntTy, - C.blockCount()) - .castAs(); + NonLoc ErrnoSVal = SVB.conjureSymbolVal(Call, C.getASTContext().IntTy, fangyi-zhou wrote: This int type is different from the call result type at times too. https://github.com/llvm/llvm-project/pull/137182 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/137182 >From 79e5875e75d46edcf15c5df536ac8f1d93e13a16 Mon Sep 17 00:00:00 2001 From: Fangyi Zhou Date: Thu, 24 Apr 2025 15:12:12 +0100 Subject: [PATCH 1/3] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events Per suggestion in https://github.com/llvm/llvm-project/pull/128251#discussion_r2055916229, adding a new helper function in `SValBuilder` to conjure a symbol when given a `CallEvent`. Tested manually (with assertions) that the `LocationContext *` obtained from the `CallEvent` are identical to those passed in the original argument. --- .../Core/PathSensitive/SValBuilder.h | 8 - .../Checkers/CStringChecker.cpp | 32 +++ .../Checkers/ErrnoTesterChecker.cpp | 3 +- .../RetainCountChecker/RetainCountChecker.cpp | 3 +- .../Checkers/SmartPtrModeling.cpp | 2 +- .../Checkers/StdLibraryFunctionsChecker.cpp | 10 +++--- .../Checkers/cert/InvalidPtrChecker.cpp | 4 +-- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 25 +-- 8 files changed, 42 insertions(+), 45 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 54430d426a82a..3f3e6bdb9ff3d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -46,10 +46,10 @@ class Stmt; namespace ento { +class CallEvent; class ConditionTruthVal; class ProgramStateManager; class StoreRef; - class SValBuilder { virtual void anchor(); @@ -209,6 +209,12 @@ class SValBuilder { const LocationContext *LCtx, QualType type, unsigned visitCount); + DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, QualType type, +unsigned visitCount, +const void *symbolTag = nullptr); + DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, +unsigned visitCount, +const void *symbolTag = nullptr); /// Conjure a symbol representing heap allocated memory region. /// diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 39dcaf02dbe25..9d3eda8f7f982 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -1514,8 +1514,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call, // If we don't know how much we copied, we can at least // conjure a return value for later. if (lastElement.isUnknown()) -lastElement = C.getSValBuilder().conjureSymbolVal( -nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); +lastElement = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); // The byte after the last byte copied is the return value. state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement); @@ -1665,8 +1664,7 @@ 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(Call, C.blockCount()); State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV); C.addTransition(State); } @@ -1769,8 +1767,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // no guarantee the full string length will actually be returned. // 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()); + result = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); NonLoc resultNL = result.castAs(); if (strLengthNL) { @@ -1793,8 +1790,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, // If we don't know the length of the string, conjure a return // value, so it can be used in constraints, at least. if (result.isUnknown()) { - result = C.getSValBuilder().conjureSymbolVal( - nullptr, Call.getOriginExpr(), LCtx, C.blockCount()); + result = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount()); } } @@ -2261,8 +2257,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
[clang] [Clang][analyzer] replace Stmt& with ConstCFGElement in SymbolConjured (reland) (PR #137355)
fangyi-zhou wrote: Range diff against previous PR: https://gist.github.com/fangyi-zhou/7d3a73a9b95f93755af3e823228c7a0d https://github.com/llvm/llvm-project/pull/137355 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][analyzer][NFC] Add a helper for conjuring symbols at call events (PR #137182)
fangyi-zhou wrote: On first look the buildbot failure seems to be unrelated to this change https://github.com/llvm/llvm-project/pull/137182 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
@@ -2556,10 +2556,19 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt(); if (!isa_and_nonnull(Term)) return; + +// FIXME: fangyi-zhou wrote: I suspect we need to actually provide a valid CFG element here, so maybe we need to pass the first element in the new CFG Block? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElementRef in SymbolConjured (PR #128251)
fangyi-zhou wrote: Looks like there's an Asan issue at the stale CFG element for loop widening https://lab.llvm.org/buildbot/#/builders/55/builds/10398. Do we need to revert? https://github.com/llvm/llvm-project/pull/128251 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElement in SymbolConjured (reland) (PR #137355)
https://github.com/fangyi-zhou edited https://github.com/llvm/llvm-project/pull/137355 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElement in SymbolConjured (reland) (PR #137355)
fangyi-zhou wrote: @steakhal https://github.com/llvm/llvm-project/pull/137355 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElement in SymbolConjured (reland) (PR #137355)
fangyi-zhou wrote: gentle ping https://github.com/llvm/llvm-project/pull/137355 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][analyzer] replace Stmt* with ConstCFGElement in SymbolConjured (reland) (PR #137355)
https://github.com/fangyi-zhou updated https://github.com/llvm/llvm-project/pull/137355 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits