https://github.com/steakhal created 
https://github.com/llvm/llvm-project/pull/238414

Node creation (addTransition, addSink, generateNonFatalErrorNode) returns null 
when the node already exists or the state is overconstrained. Several callers 
dereferenced or reported against the result unchecked.

Fixes:
- MPIChecker: 3 sites (double nonblocking, unmatched/missing wait)
- NullabilityChecker: reportBugIfInvariantHolds got null from 4 callers and 
from its own addTransition
- DynamicTypeChecker, DynamicTypePropagation, PutenvStackArrayChecker
- Unit test checkers that fed addSink() into a bug report unchecked

Fixes #64647
Authored-By: Claude

From 152e02e649378fe8f897ab10579c4de381c0d36d Mon Sep 17 00:00:00 2001
From: Balazs Benics <[email protected]>
Date: Tue, 3 Nov 2026 15:50:40 +0000
Subject: [PATCH] [analyzer] Handle null nodes from CheckerContext node
 creation

Node creation (addTransition, addSink, generateNonFatalErrorNode) returns
null when the node already exists or the state is overconstrained.
Several callers dereferenced or reported against the result unchecked.

Fixes:
- MPIChecker: 3 sites (double nonblocking, unmatched/missing wait)
- NullabilityChecker: reportBugIfInvariantHolds got null from 4 callers
  and from its own addTransition
- DynamicTypeChecker, DynamicTypePropagation, PutenvStackArrayChecker
- Unit test checkers that fed addSink() into a bug report unchecked

Fixes #64647
Authored-By: Claude
---
 clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp    | 6 ++++--
 .../lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp  | 4 ++--
 .../lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp  | 6 ++++++
 clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp    | 4 ++++
 .../lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp | 2 ++
 .../StaticAnalyzer/BugReportInterestingnessTest.cpp         | 2 ++
 clang/unittests/StaticAnalyzer/CheckLifetimeEndTest.cpp     | 2 +-
 .../unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp | 5 +++--
 8 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
index 40941f09df511b..7a60f37ef35278 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
@@ -72,8 +72,10 @@ void DynamicTypeChecker::reportTypeError(QualType 
DynamicType,
   QualType::print(StaticType.getTypePtr(), Qualifiers(), OS, C.getLangOpts(),
                   llvm::Twine());
   OS << "'";
-  auto R = std::make_unique<PathSensitiveBugReport>(
-      BT, OS.str(), C.generateNonFatalErrorNode());
+  ExplodedNode *N = C.generateNonFatalErrorNode();
+  if (!N)
+    return;
+  auto R = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
   R->markInteresting(Reg);
   R->addVisitor(std::make_unique<DynamicTypeBugVisitor>(Reg));
   R->addRange(ReportedNode->getSourceRange());
diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp 
b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 6eb57698102124..c5587c1a146557 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -887,8 +887,8 @@ void DynamicTypePropagation::checkPreObjCMessage(const 
ObjCMethodCall &M,
     // Warn when argument is incompatible with the parameter.
     if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType,
                                          ArgObjectPtrType)) {
-      ExplodedNode *N = C.generateNonFatalErrorNode(State);
-      reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg);
+      if (ExplodedNode *N = C.generateNonFatalErrorNode(State))
+        reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, 
Arg);
       return;
     }
   }
diff --git a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
index 2932cc1336571c..903a6b9586a3e3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
@@ -43,6 +43,8 @@ void MPIChecker::checkDoubleNonblocking(const CallEvent 
&PreCallEvent,
   // double nonblocking detected
   if (Req && Req->CurrentState == Request::State::Nonblocking) {
     ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode();
+    if (!ErrorNode)
+      return;
     BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode,
                                       Ctx.getBugReporter());
     Ctx.addTransition(ErrorNode->getState(), ErrorNode);
@@ -82,6 +84,8 @@ void MPIChecker::checkUnmatchedWaits(const CallEvent 
&PreCallEvent,
     if (!Req) {
       if (!ErrorNode) {
         ErrorNode = Ctx.generateNonFatalErrorNode(State);
+        if (!ErrorNode)
+          return;
         State = ErrorNode->getState();
       }
       // A wait has no matching nonblocking call.
@@ -113,6 +117,8 @@ void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper,
 
         if (!ErrorNode) {
           ErrorNode = Ctx.generateNonFatalErrorNode(State);
+          if (!ErrorNode)
+            return;
           State = ErrorNode->getState();
         }
         BReporter.reportMissingWait(Req.second, Req.first, ErrorNode,
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index e1c7f7ec62150c..fd82fa2ff92a58 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -477,6 +477,8 @@ void NullabilityChecker::reportBugIfInvariantHolds(
     StringRef Msg, ErrorKind Error, const BugType &BT, ExplodedNode *N,
     const MemRegion *Region, CheckerContext &C, const Stmt *ValueExpr,
     bool SuppressPath) const {
+  if (!N)
+    return;
   ProgramStateRef OriginalState = N->getState();
 
   if (checkInvariantViolation(OriginalState, N, C))
@@ -484,6 +486,8 @@ void NullabilityChecker::reportBugIfInvariantHolds(
   if (SuppressPath) {
     OriginalState = OriginalState->set<InvariantViolated>(true);
     N = C.addTransition(OriginalState, N);
+    if (!N)
+      return;
   }
 
   reportBug(Msg, Error, BT, N, Region, C.getBugReporter(), ValueExpr);
diff --git a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
index 69913d92d23c4f..a1bf32239f3f30 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PutenvStackArrayChecker.cpp
@@ -59,6 +59,8 @@ void PutenvStackArrayChecker::checkPostCall(const CallEvent 
&Call,
   StringRef ErrorMsg = "The 'putenv' function should not be called with "
                        "arrays that have automatic storage";
   ExplodedNode *N = C.addSink();
+  if (!N)
+    return;
   auto Report = std::make_unique<PathSensitiveBugReport>(BT, ErrorMsg, N);
 
   // Track the argument.
diff --git a/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp 
b/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
index b757777a4a8070..3e13222f38ca8d 100644
--- a/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
+++ b/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp
@@ -98,6 +98,8 @@ void InterestingnessTestChecker::handleCheck(const CallEvent 
&Call,
 void InterestingnessTestChecker::handleBug(const CallEvent &Call,
                                            CheckerContext &C) const {
   ExplodedNode *N = C.addSink();
+  if (!N)
+    return;
   C.emitReport(
       std::make_unique<PathSensitiveBugReport>(BT_TestBug, "test bug", N));
 }
diff --git a/clang/unittests/StaticAnalyzer/CheckLifetimeEndTest.cpp 
b/clang/unittests/StaticAnalyzer/CheckLifetimeEndTest.cpp
index 03185f63b5fc83..59e6b5dbaa1488 100644
--- a/clang/unittests/StaticAnalyzer/CheckLifetimeEndTest.cpp
+++ b/clang/unittests/StaticAnalyzer/CheckLifetimeEndTest.cpp
@@ -41,7 +41,7 @@ class LifetimeEndReporter : public 
Checker<check::LifetimeEnd> {
                                      D->getDeclName().getAsString(), Count);
 
     ExplodedNode *Node = C.generateNonFatalErrorNode(State);
-    EXPECT_TRUE(Node != nullptr);
+    ASSERT_TRUE(Node != nullptr);
 
     auto Report = std::make_unique<PathSensitiveBugReport>(
         LifetimeEndNode, Description.str(), Node);
diff --git a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp 
b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
index 12c0387de6ae9c..9a55d156962701 100644
--- a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
+++ b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
@@ -93,8 +93,9 @@ class CheckerRegistrationOrderPrinter
 
 public:
   void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
-    ExplodedNode *N = nullptr;
-    N = C.addSink();
+    ExplodedNode *N = C.addSink();
+    if (!N)
+      return;
     llvm::SmallString<200> Buf;
     llvm::raw_svector_ostream OS(Buf);
     C.getAnalysisManager()

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to