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
