https://github.com/tigbr updated https://github.com/llvm/llvm-project/pull/212186
From 89967a66b4a656feaf71921dbb2c841f8aef31d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Thu, 23 Jul 2026 17:17:28 +0200 Subject: [PATCH 01/23] Remove `NodeBuilder` from `ExprEngine::VisitCompoundLiteralExpr`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 3e7973769f091..8e142334103b7 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -545,8 +545,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - NodeBuilder B(Pred, Dst, *currBldrCtx); - ProgramStateRef State = Pred->getState(); const StackFrame *SF = Pred->getStackFrame(); @@ -564,7 +562,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, V = CLLoc; } - B.generateNode(CL, Pred, State->BindExpr(CL, SF, V)); + Dst.insert(Engine.makeNodeWithBinding(Pred, CL, V, State)); } void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, From 2ec7d9a1f249759ab50f6808ed619e9e15f0f72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 10:16:06 +0200 Subject: [PATCH 02/23] Remove `NodeBuilder` from `ExprEngine::VisitUnaryExprOrTypeTraitExpr`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 8e142334103b7..2b73a6e69132c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -846,8 +846,6 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this); ExplodedNodeSet EvalSet; - NodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); - QualType T = Ex->getTypeOfArgument(); for (ExplodedNode *N : CheckedSet) { @@ -858,11 +856,13 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, // FIXME: Add support for VLA type arguments and VLA expressions. // When that happens, we should probably refactor VLASizeChecker's code. + EvalSet.insert(N); continue; } else if (T->getAs<ObjCObjectType>()) { // Some code tries to take the sizeof an ObjCObjectType, relying that // the compiler has laid out its representation. Just report Unknown // for these. + EvalSet.insert(N); continue; } } @@ -870,11 +870,8 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, APSInt Value = Ex->EvaluateKnownConstInt(getContext()); CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); - ProgramStateRef state = N->getState(); - state = state->BindExpr( - Ex, N->getStackFrame(), - svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType())); - Bldr.generateNode(Ex, N, state); + SVal V = svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType()); + EvalSet.insert(Engine.makeNodeWithBinding(N, Ex, V)); } getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); From 1d53110853ef1e1ae431ec79f38cb075af7e539f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 14:20:41 +0200 Subject: [PATCH 03/23] Remove `NodeBuilder` from `ExprEngine::VisitGuardedExpr`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 2b73a6e69132c..104a5074b6a22 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -762,7 +762,6 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, ExplodedNodeSet &Dst) { assert(L && R); - NodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const StackFrame *SF = Pred->getStackFrame(); const CFGBlock *SrcBlock = nullptr; @@ -816,7 +815,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, getNumVisitedCurrent()); // Generate a new node with the binding from the appropriate path. - B.generateNode(Ex, Pred, state->BindExpr(Ex, SF, V, true)); + Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, V)); } void ExprEngine:: From 67a9961ef9c48454fa8bc44fb8bc9dc8e4efc9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 14:28:04 +0200 Subject: [PATCH 04/23] Remove `NodeBuilder` from `ExprEngine::VisitOffsetOfExpr`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 104a5074b6a22..752abdc1943ed 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -818,10 +818,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, V)); } -void ExprEngine:: -VisitOffsetOfExpr(const OffsetOfExpr *OOE, - ExplodedNode *Pred, ExplodedNodeSet &Dst) { - NodeBuilder B(Pred, Dst, *currBldrCtx); +void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { Expr::EvalResult Result; if (OOE->EvaluateAsInt(Result, getContext())) { APSInt IV = Result.Val.getInt(); @@ -829,13 +827,11 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE, assert(OOE->getType()->castAs<BuiltinType>()->isInteger()); assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); SVal X = svalBuilder.makeIntVal(IV); - B.generateNode(OOE, Pred, - Pred->getState()->BindExpr(OOE, Pred->getStackFrame(), X)); + Dst.insert(Engine.makeNodeWithBinding(Pred, OOE, X)); } // FIXME: Handle the case where __builtin_offsetof is not a constant. } - void ExprEngine:: VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred, From a4d10a4b90e5c5c8a84ddc73eaa9bf2bddf8666c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 15:35:00 +0200 Subject: [PATCH 05/23] Remove `NodeBuilder` from `ExprEngine::evalLocation`. --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 7669b65818272..b52a295c69536 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3661,23 +3661,20 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, } } -void ExprEngine::evalLocation(ExplodedNodeSet &Dst, - const Stmt *NodeEx, - const Stmt *BoundEx, - ExplodedNode *Pred, - ProgramStateRef state, - SVal location, +void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *NodeEx, + const Stmt *BoundEx, ExplodedNode *Pred, + ProgramStateRef state, SVal location, bool isLoad) { - NodeBuilder BldrTop(Pred, Dst, *currBldrCtx); // Early checks for performance reason. if (location.isUnknown()) { + Dst.insert(Pred); return; } ExplodedNodeSet Src; - BldrTop.takeNodes(Pred); - NodeBuilder Bldr(Pred, Src, *currBldrCtx); - if (Pred->getState() != state) { + if (Pred->getState() == state) { + Src.insert(Pred); + } else { // Associate this new state with an ExplodedNode. // FIXME: If I pass null tag, the graph is incorrect, e.g for // int *p; @@ -3688,12 +3685,15 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, // "Variable 'p' initialized to a null pointer value" static SimpleProgramPointTag tag(TagProviderName, "Location"); - Bldr.generateNode(NodeEx, Pred, state, &tag); + const ProgramPoint &L = ProgramPoint::getProgramPoint( + NodeEx, ProgramPoint::PostStmtKind, Pred->getStackFrame(), &tag); + Src.insert(Engine.makeNode(L, state, Pred)); } + ExplodedNodeSet Tmp; getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, NodeEx, BoundEx, *this); - BldrTop.addNodes(Tmp); + Dst.insert(Tmp); } std::pair<const ProgramPointTag *, const ProgramPointTag *> From 7442b7c54ac4bfa656d98f05dcbe2bce6c5f9342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 15:50:10 +0200 Subject: [PATCH 06/23] Remove `NodeBuilder` from `ExprEngine::VisitLogicalExpr`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 752abdc1943ed..d10677b02be52 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -683,7 +683,6 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); if (B->getType()->isVectorType()) { @@ -692,7 +691,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, // logical operators on vectors are not short-circuit. Currently they are // modeled as short-circuit in Clang CFG but this is incorrect. // Do not set the value for the expression. It'd be UnknownVal by default. - Bldr.generateNode(B, Pred, state); + Dst.insert(Engine.makePostStmtNode(B, state, Pred)); return; } @@ -704,7 +703,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, (void) P; if (N->pred_size() != 1) { // We failed to track back where we came from. - Bldr.generateNode(B, Pred, state); + Dst.insert(Engine.makePostStmtNode(B, state, Pred)); return; } N = *N->pred_begin(); @@ -712,7 +711,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, if (N->pred_size() != 1) { // We failed to track back where we came from. - Bldr.generateNode(B, Pred, state); + Dst.insert(Engine.makePostStmtNode(B, state, Pred)); return; } @@ -752,7 +751,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, svalBuilder.makeZeroVal(RHS->getType()), B->getType()); } } - Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getStackFrame(), X)); + Dst.insert(Engine.makeNodeWithBinding(Pred, B, X)); } void ExprEngine::VisitGuardedExpr(const Expr *Ex, From 14b4954873a3e1bb6da6cfcaccd604104f06f318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 17:33:57 +0200 Subject: [PATCH 07/23] Remove `NodeBuilder` from `ExprEngine::VisitCast`. --- .../Core/PathSensitive/ExprEngine.h | 2 +- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 51 ++++++++----------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index b725db1d6256f..f3b4f6f3cecb1 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -679,7 +679,7 @@ class ExprEngine { ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex, const StackFrame *SF, QualType T, QualType ExTy, const CastExpr *CastE, - NodeBuilder &Bldr, ExplodedNode *Pred); + ExplodedNodeSet &Dst, ExplodedNode *Pred); public: SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op, diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index d10677b02be52..fcce70f7ffde2 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -226,7 +226,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ProgramStateRef ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex, const StackFrame *SF, QualType T, QualType ExTy, - const CastExpr *CastE, NodeBuilder &Bldr, + const CastExpr *CastE, ExplodedNodeSet &Dst, ExplodedNode *Pred) { if (T->isLValueReferenceType()) { assert(!CastE->getType()->isLValueReferenceType()); @@ -247,7 +247,7 @@ ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex, if (V.isUnknown() && !OrigV.isUnknown()) { state = escapeValues(state, OrigV, PSK_EscapeOther); } - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makePostStmtNode(CastE, state, Pred)); return state; } @@ -279,7 +279,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, } // Simulate the operation that actually casts the original value to a new // value of the destination type : - NodeBuilder Bldr(DstEvalLoc, Dst, *currBldrCtx); for (ExplodedNode *Node : DstEvalLoc) { ProgramStateRef State = Node->getState(); @@ -294,8 +293,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, CastedV = svalBuilder.evalCast(svalBuilder.simplifySVal(State, OrigV), CastE->getType(), Ex->getType()); } - State = State->BindExpr(CastE, SF, CastedV); - Bldr.generateNode(CastE, Node, State); + Dst.insert(Engine.makeNodeWithBinding(Node, CastE, CastedV)); } return; } @@ -307,7 +305,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); - NodeBuilder Bldr(DstPreStmt, Dst, *currBldrCtx); for (ExplodedNode *Pred : DstPreStmt) { ProgramStateRef state = Pred->getState(); const StackFrame *SF = Pred->getStackFrame(); @@ -317,6 +314,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_LValueToRValueBitCast: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: + Dst.insert(Pred); continue; // The analyzer doesn't do anything special with these casts, // since it understands retain/release semantics already. @@ -341,8 +339,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ProgramStateRef state = Pred->getState(); const StackFrame *SF = Pred->getStackFrame(); SVal V = state->getSVal(Ex, SF); - state = state->BindExpr(CastE, SF, V); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V)); continue; } case CK_MemberPointerToBoolean: @@ -352,12 +349,11 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (PTMSV) V = svalBuilder.makeTruthVal(!PTMSV->isNullMemberPointer(), ExTy); if (V.isUndef() || PTMSV) { - state = state->BindExpr(CastE, SF, V); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V)); continue; } // Explicitly proceed with default handler for this case cascade. - state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred); + state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred); continue; } case CK_Dependent: @@ -369,12 +365,11 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_PointerToIntegral: { SVal V = state->getSVal(Ex, SF); if (isa<nonloc::PointerToMember>(V)) { - state = state->BindExpr(CastE, SF, UnknownVal()); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V)); continue; } // Explicitly proceed with default handler for this case cascade. - state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred); + state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred); continue; } case CK_IntegralToBoolean: @@ -405,7 +400,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_FixedPointToBoolean: case CK_FixedPointToIntegral: case CK_IntegralToFixedPoint: { - state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Bldr, Pred); + state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred); continue; } case CK_IntegralCast: { @@ -415,8 +410,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, V = svalBuilder.evalCast(V, T, ExTy); else V = svalBuilder.evalIntegralCast(state, V, T, ExTy); - state = state->BindExpr(CastE, SF, V); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V)); continue; } case CK_DerivedToBase: @@ -424,8 +418,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // For DerivedToBase cast, delegate to the store manager. SVal val = state->getSVal(Ex, SF); val = getStoreManager().evalDerivedToBase(val, CastE); - state = state->BindExpr(CastE, SF, val); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val)); continue; } // Handle C++ dyn_cast. @@ -451,7 +444,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (T->isReferenceType()) { // A bad_cast exception is thrown if input value is a reference. // Currently, we model this, by generating a sink. - Bldr.generateSink(CastE, Pred, state); + Dst.insert(Engine.makePostStmtNode(CastE, state, Pred, + /* MarkAsSink */ true)); continue; } else { // If the cast fails on a pointer, bind to 0. @@ -469,7 +463,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, // Else, bind to the derived region value. state = state->BindExpr(CastE, SF, val); } - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makePostStmtNode(CastE, state, Pred)); continue; } case CK_BaseToDerived: { @@ -489,20 +483,17 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType, getNumVisitedCurrent()); } - state = state->BindExpr(CastE, SF, val); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val)); continue; } case CK_NullToPointer: { SVal V = svalBuilder.makeNullWithType(CastE->getType()); - state = state->BindExpr(CastE, SF, V); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V)); continue; } case CK_NullToMemberPointer: { SVal V = svalBuilder.getMemberPointer(nullptr); - state = state->BindExpr(CastE, SF, V); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V)); continue; } case CK_DerivedToBaseMemberPointer: @@ -513,8 +504,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, SVal CastedPTMSV = svalBuilder.makePointerToMember(getBasicVals().accumCXXBase( CastE->path(), *PTMSV, CastE->getCastKind())); - state = state->BindExpr(CastE, SF, CastedPTMSV); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, CastedPTMSV)); continue; } // Explicitly proceed with default handler for this case cascade. @@ -534,8 +524,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, SVal result = svalBuilder.conjureSymbolVal( /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType, getNumVisitedCurrent()); - state = state->BindExpr(CastE, SF, result); - Bldr.generateNode(CastE, Pred, state); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, result)); continue; } } From dc876aaf46d65273103139661435e7f9b0d74161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 17:49:18 +0200 Subject: [PATCH 08/23] Remove `NodeBuilder` from `ExprEngine::VisitDeclStmt`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index fcce70f7ffde2..07ad6a42dfbef 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -603,7 +603,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); ExplodedNodeSet dstEvaluated; - NodeBuilder B(dstPreVisit, dstEvaluated, *currBldrCtx); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { ExplodedNode *N = *I; @@ -622,7 +621,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, state = finishObjectConstruction(state, DS, SF); // We constructed the object directly in the variable. // No need to bind anything. - B.generateNode(DS, UpdatedN, state); + dstEvaluated.insert(Engine.makePostStmtNode(DS, state, UpdatedN)); } else { // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. @@ -637,19 +636,15 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, getNumVisitedCurrent()); } - - B.takeNodes(UpdatedN); - ExplodedNodeSet Dst2; - evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, SF), InitVal, true); - B.addNodes(Dst2); + evalBind(dstEvaluated, DS, UpdatedN, state->getLValue(VD, SF), InitVal, true); } } else { - B.generateNode(DS, N, state); + dstEvaluated.insert(Engine.makePostStmtNode(DS, state, N)); } } - getCheckerManager().runCheckersForPostStmt(Dst, B.getResults(), DS, *this); + getCheckerManager().runCheckersForPostStmt(Dst, dstEvaluated, DS, *this); } void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, From 0c076fd66c2248331242c2d82fe16b23a3b15702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 17:58:08 +0200 Subject: [PATCH 09/23] Remove `NodeBuilder` from `ExprEngine::VisitIncrementDecrementOperator`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 07ad6a42dfbef..95577073d7065 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -1007,7 +1007,6 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, evalLoad(Tmp, U, Ex, Pred, state, loc); ExplodedNodeSet Dst2; - NodeBuilder Bldr(Tmp, Dst2, *currBldrCtx); for (ExplodedNode *N : Tmp) { state = N->getState(); assert(SF == N->getStackFrame()); @@ -1018,11 +1017,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, state = state->BindExpr(U, SF, V2_untested); // Perform the store, so that the uninitialized value detection happens. - Bldr.takeNodes(N); - ExplodedNodeSet Dst3; - evalStore(Dst3, U, Ex, N, state, loc, V2_untested); - Bldr.addNodes(Dst3); - + evalStore(Dst2, U, Ex, N, state, loc, V2_untested); continue; } DefinedSVal V2 = V2_untested.castAs<DefinedSVal>(); @@ -1086,10 +1081,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, state = state->BindExpr(U, SF, U->isPostfix() ? V2 : Result); // Perform the store. - Bldr.takeNodes(N); - ExplodedNodeSet Dst3; - evalStore(Dst3, U, Ex, N, state, loc, Result); - Bldr.addNodes(Dst3); + evalStore(Dst2, U, Ex, N, state, loc, Result); } Dst.insert(Dst2); } From 91d848a98f7b7eec7817a2cef35a2963e0cc08ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 18:17:56 +0200 Subject: [PATCH 10/23] Remove `NodeBuilder` from `ExprEngine::evalLoad`. --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index b52a295c69536..9cb2dc2e25198 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3640,9 +3640,10 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, if (Tmp.empty()) return; - NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); - if (location.isUndef()) + if (location.isUndef()) { + Dst.insert(Tmp); return; + } // Proceed with the load. for (const auto I : Tmp) { @@ -3655,9 +3656,10 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst, V = state->getSVal(location.castAs<Loc>(), LoadTy); } - Bldr.generateNode(NodeEx, I, - state->BindExpr(BoundEx, I->getStackFrame(), V), tag, - ProgramPoint::PostLoadKind); + const auto *SF = I->getStackFrame(); + const auto &Loc = ProgramPoint::getProgramPoint( + NodeEx, ProgramPoint::PostLoadKind, SF, tag); + Dst.insert(Engine.makeNode(Loc, state->BindExpr(BoundEx, SF, V), I)); } } From 4a5f929757a2c8a2435ec08e33007e2c270b089f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 18:22:12 +0200 Subject: [PATCH 11/23] Pass EvalSet to `evalLoad` directly since it no longer uses `NodeBuilder`. --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 9cb2dc2e25198..4572aa43a6355 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3351,7 +3351,6 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, for (const auto I : CheckedSet) VisitCommonDeclRefExpr(M, Member, I, EvalSet); } else { - ExplodedNodeSet Tmp; for (const auto I : CheckedSet) { ProgramStateRef state = I->getState(); @@ -3412,10 +3411,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, EvalSet.insert(Engine.makeNodeWithBinding( I, M, L, state, ProgramPoint::PostLValueKind)); } else { - // FIXME: When evalLoad no longer uses NodeBuilders, eliminate Tmp and - // pass EvalSet as the first argument of evalLoad. - evalLoad(Tmp, M, M, I, state, L); - EvalSet.insert(Tmp); + evalLoad(EvalSet, M, M, I, state, L); } } } From cb3d806f7bedade23978d400015e8f8be8d2a7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 18:28:39 +0200 Subject: [PATCH 12/23] Remove `NodeBuilder` from `ExprEngine::CreateCXXTemporaryObject`. --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 9c10bcbdc4c0d..38df71120a7f9 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -33,13 +33,12 @@ using namespace ento; void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); const Expr *tempExpr = ME->getSubExpr()->IgnoreParens(); ProgramStateRef state = Pred->getState(); const StackFrame *SF = Pred->getStackFrame(); state = createTemporaryRegionIfNeeded(state, SF, tempExpr, ME); - Bldr.generateNode(ME, Pred, state); + Dst.insert(Engine.makePostStmtNode(ME, state, Pred)); } void ExprEngine::performTrivialCopy(ExplodedNodeSet &Dst, ExplodedNode *Pred, From e06a2208ab6bd5d43101517699f99eee0827de70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 18:32:46 +0200 Subject: [PATCH 13/23] Remove `NodeBuilder` from `ExprEngine::VisitCXXCatchStmt`. --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 38df71120a7f9..69938d26a613b 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -1114,8 +1114,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, ProgramStateRef state = Pred->getState(); state = state->bindLoc(state->getLValue(VD, SF), V, SF); - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - Bldr.generateNode(CS, Pred, state); + Dst.insert(Engine.makePostStmtNode(CS, state, Pred)); } void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, From cd29809eeb04c8a3b6b3612ce858ef3c19066239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 18:40:31 +0200 Subject: [PATCH 14/23] Remove `NodeBuilder` from `ExprEngine::VisitCXXThisExpr`. --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 69938d26a613b..ad3e7e826564a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -1119,8 +1119,6 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - // Get the this object region from StoreManager. const StackFrame *SF = Pred->getStackFrame(); const MemRegion *R = svalBuilder.getRegionManager().getCXXThisRegion( @@ -1128,7 +1126,7 @@ void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, ProgramStateRef state = Pred->getState(); SVal V = state->getSVal(loc::MemRegionVal(R)); - Bldr.generateNode(TE, Pred, state->BindExpr(TE, SF, V)); + Dst.insert(Engine.makeNodeWithBinding(Pred, TE, V)); } void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, From 5bcf78e3879e2ca9c42ab2d2484f1317a74ee7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Fri, 24 Jul 2026 18:58:38 +0200 Subject: [PATCH 15/23] Remove `NodeBuilder` from `ExprEngine::VisitLambdaExpr`. --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index ad3e7e826564a..df801e10a974e 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -1191,14 +1191,12 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred, // to be an RValue. SVal LambdaRVal = State->getSVal(R); - ExplodedNodeSet Tmp; - NodeBuilder Bldr(Pred, Tmp, *currBldrCtx); // FIXME: is this the right program point kind? - Bldr.generateNode(LE, Pred, State->BindExpr(LE, SF, LambdaRVal), nullptr, - ProgramPoint::PostLValueKind); + ExplodedNode *N = Engine.makeNodeWithBinding(Pred, LE, LambdaRVal, State, + ProgramPoint::PostLValueKind); // FIXME: Move all post/pre visits to ::Visit(). - getCheckerManager().runCheckersForPostStmt(Dst, Tmp, LE, *this); + getCheckerManager().runCheckersForPostStmt(Dst, N, LE, *this); } void ExprEngine::VisitAttributedStmt(const AttributedStmt *A, From a423c005d9935d782c45d741a6e2e7216fe61625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Sat, 25 Jul 2026 11:10:47 +0200 Subject: [PATCH 16/23] Remove `NodeBuilder` from `ExprEngine::VisitCXXDestructor`. --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index df801e10a974e..f88df584f654c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -820,8 +820,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, // FIXME: PostImplicitCall with a null decl may crash elsewhere anyway. PostImplicitCall PP(/*Decl=*/nullptr, S->getEndLoc(), SF, getCFGElementRef(), &T); - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - Bldr.generateNode(PP, Pred->getState(), Pred); + Dst.insert(Engine.makeNode(PP, Pred->getState(), Pred)); return; } @@ -836,9 +835,9 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, Dest = MRMgr.getCXXTempObjectRegion(E, Pred->getStackFrame()); } else { static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor"); - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - Bldr.generateSink(Pred->getLocation().withTag(&T), - Pred->getState(), Pred); + Dst.insert(Engine.makeNode(Pred->getLocation().withTag(&T), + Pred->getState(), Pred, + /* MarkAsSink */ true)); return; } } From 670143668f9c7465ff7992cee300b10a1a88c7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Sat, 25 Jul 2026 11:52:40 +0200 Subject: [PATCH 17/23] Remove `NodeBuilder` from `ExprEngine::handleConstructor`. --- .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index f88df584f654c..14e3170e76b0a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -541,11 +541,10 @@ void ExprEngine::handleConstructor(const Expr *E, // it in fact constructs into the correct target. This constructor can // therefore be skipped. Target = *ElidedTarget; - NodeBuilder Bldr(Pred, destNodes, *currBldrCtx); State = finishObjectConstruction(State, CE, SF); if (auto L = Target.getAs<Loc>()) State = State->BindExpr(CE, SF, State->getSVal(*L, CE->getType())); - Bldr.generateNode(CE, Pred, State); + destNodes.insert(Engine.makePostStmtNode(CE, State, Pred)); return; } } @@ -582,10 +581,11 @@ void ExprEngine::handleConstructor(const Expr *E, // No element construction will happen in a 0 size array. if (isZeroSizeArray()) { - NodeBuilder Bldr(Pred, destNodes, *currBldrCtx); static SimpleProgramPointTag T{"ExprEngine", "Skipping 0 size array construction"}; - Bldr.generateNode(CE, Pred, State, &T); + const ProgramPoint &P = ProgramPoint::getProgramPoint( + CE, ProgramPoint::PostStmtKind, Pred->getStackFrame(), &T); + destNodes.insert(Engine.makeNode(P, State, Pred)); return; } @@ -663,10 +663,9 @@ void ExprEngine::handleConstructor(const Expr *E, if (State != Pred->getState()) { static SimpleProgramPointTag T("ExprEngine", "Prepare for object construction"); - ExplodedNodeSet DstPrepare; - NodeBuilder BldrPrepare(Pred, DstPrepare, *currBldrCtx); - Pred = - BldrPrepare.generateNode(E, Pred, State, &T, ProgramPoint::PreStmtKind); + const ProgramPoint &P = ProgramPoint::getProgramPoint( + E, ProgramPoint::PreStmtKind, Pred->getStackFrame(), &T); + Pred = Engine.makeNode(P, State, Pred); if (!Pred) return; } @@ -685,7 +684,6 @@ void ExprEngine::handleConstructor(const Expr *E, ExplodedNodeSet PreInitialized; if (CE) { // FIXME: Is it possible and/or useful to do this before PreStmt? - NodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx); for (ExplodedNode *N : DstPreVisit) { ProgramStateRef State = N->getState(); if (CE->requiresZeroInitialization()) { @@ -708,8 +706,9 @@ void ExprEngine::handleConstructor(const Expr *E, State = State->bindDefaultZero(Target, SF); } - Bldr.generateNode(CE, N, State, /*tag=*/nullptr, - ProgramPoint::PreStmtKind); + const ProgramPoint &P = ProgramPoint::getProgramPoint( + CE, ProgramPoint::PreStmtKind, N->getStackFrame(), /*tag=*/nullptr); + PreInitialized.insert(Engine.makeNode(P, State, N)); } } else { PreInitialized = DstPreVisit; @@ -742,7 +741,6 @@ void ExprEngine::handleConstructor(const Expr *E, // later (for life-time extended temporaries) -- but avoids infeasible // paths when no-return temporary destructors are used for assertions. ExplodedNodeSet DstEvaluatedPostProcessed; - NodeBuilder Bldr(DstEvaluated, DstEvaluatedPostProcessed, *currBldrCtx); const AnalysisDeclContext *ADC = SF->getAnalysisDeclContext(); if (!ADC->getCFGBuildOptions().AddTemporaryDtors) { if (llvm::isa_and_nonnull<CXXTempObjectRegion, @@ -762,7 +760,8 @@ void ExprEngine::handleConstructor(const Expr *E, "We should not have inlined this constructor!"); for (ExplodedNode *N : DstEvaluated) { - Bldr.generateSink(E, N, N->getState()); + DstEvaluatedPostProcessed.insert(Engine.makePostStmtNode( + E, N->getState(), N, /* MarkAsSink */ true)); } // There is no need to run the PostCall and PostStmt checker @@ -772,6 +771,7 @@ void ExprEngine::handleConstructor(const Expr *E, } } + DstEvaluatedPostProcessed.insert(DstEvaluated); ExplodedNodeSet DstPostArgumentCleanup; for (ExplodedNode *I : DstEvaluatedPostProcessed) finishArgumentConstruction(DstPostArgumentCleanup, I, *Call); From c3cc1b1a97b8a0d412ae80ed42c338902d79ff06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Sat, 25 Jul 2026 12:06:51 +0200 Subject: [PATCH 18/23] Remove `NodeBuilder` from `ExprEngine::VisitCXXNewAllocatorCall`. --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 14e3170e76b0a..54ec3ad37d293 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -895,7 +895,6 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, // Store return value of operator new() for future use, until the actual // CXXNewExpr gets processed. ExplodedNodeSet DstPostValue; - NodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx); for (ExplodedNode *I : DstPostCall) { // FIXME: Because CNE serves as the "call site" for the allocator (due to // lack of a better expression in the AST), the conjured return value symbol @@ -928,8 +927,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, State = State->assume(RetVal.castAs<DefinedOrUnknownSVal>(), true); } - ValueBldr.generateNode(CNE, I, - addObjectUnderConstruction(State, CNE, SF, RetVal)); + DstPostValue.insert(Engine.makePostStmtNode( + CNE, addObjectUnderConstruction(State, CNE, SF, RetVal), I)); } ExplodedNodeSet DstPostPostCallCallback; From 190299e77e7fbddd04d482ffc178e2bc84ee691f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Sat, 25 Jul 2026 17:22:17 +0200 Subject: [PATCH 19/23] Remove `NodeBuilder` from `ExprEngine::VisitCXXNewExpr`. --- .../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 54ec3ad37d293..1d7479680d599 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -1000,8 +1000,6 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, State = State->assume(*dSymVal, true); } - NodeBuilder Bldr(Pred, Dst, *currBldrCtx); - SVal Result = symVal; if (CNE->isArray()) { @@ -1024,23 +1022,21 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // If the array is list initialized, we bind the initializer list to the // memory region here, otherwise we would lose it. if (isInitList) { - Bldr.takeNodes(Pred); - Pred = Bldr.generateNode(CNE, Pred, State); + Pred = Engine.makePostStmtNode(CNE, State, Pred); SVal V = State->getSVal(Init, SF); ExplodedNodeSet evaluated; evalBind(evaluated, CNE, Pred, Result, V, true); - Bldr.takeNodes(Pred); - Bldr.addNodes(evaluated); + Dst.insert(evaluated); Pred = *evaluated.begin(); State = Pred->getState(); } } - State = State->BindExpr(CNE, Pred->getStackFrame(), Result); - Bldr.generateNode(CNE, Pred, State); + Dst.erase(Pred); + Dst.insert(Engine.makeNodeWithBinding(Pred, CNE, Result, State)); return; } @@ -1056,8 +1052,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, } // Bind the address of the object, then check to see if we cached out. - State = State->BindExpr(CNE, SF, Result); - ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State); + ExplodedNode *NewN = Engine.makeNodeWithBinding(Pred, CNE, Result, State); + Dst.insert(NewN); if (!NewN) return; @@ -1065,8 +1061,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // initializer. Copy the value over. if (const Expr *Init = CNE->getInitializer()) { if (!isa<CXXConstructExpr>(Init)) { - assert(Bldr.getResults().size() == 1); - Bldr.takeNodes(NewN); + assert(Dst.size() == 1); + Dst.erase(NewN); evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, SF), /*FirstInit=*/IsStandardGlobalOpNewFunction); } From e2c3199d02ebafa4e7bb3734c0d53f1770d4378f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Mon, 27 Jul 2026 09:21:32 +0200 Subject: [PATCH 20/23] Formatting. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 7 ++++--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 95577073d7065..bf48a8955197f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -621,7 +621,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, state = finishObjectConstruction(state, DS, SF); // We constructed the object directly in the variable. // No need to bind anything. - dstEvaluated.insert(Engine.makePostStmtNode(DS, state, UpdatedN)); + dstEvaluated.insert(Engine.makePostStmtNode(DS, state, UpdatedN)); } else { // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. @@ -636,11 +636,12 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, getNumVisitedCurrent()); } - evalBind(dstEvaluated, DS, UpdatedN, state->getLValue(VD, SF), InitVal, true); + evalBind(dstEvaluated, DS, UpdatedN, state->getLValue(VD, SF), InitVal, + true); } } else { - dstEvaluated.insert(Engine.makePostStmtNode(DS, state, N)); + dstEvaluated.insert(Engine.makePostStmtNode(DS, state, N)); } } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 1d7479680d599..0f90a7195032a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -1112,7 +1112,7 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, } void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { + ExplodedNodeSet &Dst) { // Get the this object region from StoreManager. const StackFrame *SF = Pred->getStackFrame(); const MemRegion *R = svalBuilder.getRegionManager().getCXXThisRegion( From 316711adf34cd43f14e6a339a98ec0b5344ae152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Mon, 27 Jul 2026 14:11:21 +0200 Subject: [PATCH 21/23] Fix accidental change of bind value back to `UnknownVal()`. --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index bf48a8955197f..d22117544f17e 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -365,7 +365,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_PointerToIntegral: { SVal V = state->getSVal(Ex, SF); if (isa<nonloc::PointerToMember>(V)) { - Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V)); + Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, UnknownVal())); continue; } // Explicitly proceed with default handler for this case cascade. From b43428d14a0decdec22a1a7b4bac3b9f86909e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Mon, 27 Jul 2026 14:23:32 +0200 Subject: [PATCH 22/23] Fix missing insert into destination set in `ExprEngine::VisitOffsetOfExpr` --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index d22117544f17e..b815587675379 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -812,8 +812,10 @@ void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred, assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); SVal X = svalBuilder.makeIntVal(IV); Dst.insert(Engine.makeNodeWithBinding(Pred, OOE, X)); + } else { + // FIXME: Handle the case where __builtin_offsetof is not a constant. + Dst.insert(Pred); } - // FIXME: Handle the case where __builtin_offsetof is not a constant. } void ExprEngine:: From f0dce6816a8c742f69f80154019db52089bf9dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20T=C3=B3thv=C3=A1ri?= <[email protected]> Date: Mon, 27 Jul 2026 15:44:48 +0200 Subject: [PATCH 23/23] Add test for the scenario when __builtin_offsetof is non-constant. --- clang/test/Analysis/misc-ps.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/test/Analysis/misc-ps.m b/clang/test/Analysis/misc-ps.m index c22e0dbb6137d..e6f665d68a8d6 100644 --- a/clang/test/Analysis/misc-ps.m +++ b/clang/test/Analysis/misc-ps.m @@ -622,6 +622,15 @@ void test_offsetof_4(void) { *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}} } +// Test when __builtin_offsetof is not constant-foldable. +struct test_offsetof_5_struct { int a; int arr[10]; }; +int test_offsetof_5(int i) { + int *p = 0; + unsigned long off = __builtin_offsetof(struct test_offsetof_5_struct, arr[i]); + (void)off; + return *p; // expected-warning{{Dereference of null pointer}} +} + // "nil receiver" false positive: make tracking of the MemRegion for 'self' // path-sensitive @interface RDar6829164 : NSObject { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
