https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/215409
>From c2cd1ff1c6cee173fd9381a353b288fc77481aaa Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Mon, 10 Aug 2026 23:43:34 +0200 Subject: [PATCH 1/2] [analyzer] Only report the first dereference of the same variable in DanglingPtrDeref --- .../StaticAnalyzer/Checkers/DanglingPtrDeref.cpp | 6 ++++++ .../StaticAnalyzer/Checkers/LifetimeModeling.cpp | 8 ++++++++ .../lib/StaticAnalyzer/Checkers/LifetimeModeling.h | 5 +++++ clang/test/Analysis/dangling-ptr-deref.cpp | 13 +++++++++++++ 4 files changed, 32 insertions(+) diff --git a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp index bd4cd864cb768..cd690328ebc47 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp @@ -69,6 +69,11 @@ void DanglingPtrDeref::checkPostCall(const CallEvent &Call, void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region, const Stmt *S, ExplodedNode *N, CheckerContext &C) const { + ProgramStateRef ReportedState = + lifetime_modeling::markAsReported(N->getState(), Region); + if (!ReportedState) + return; + auto BR = std::make_unique<PathSensitiveBugReport>( BugMsg, (llvm::Twine("Use of ") + lifetime_modeling::getRegionName(Region) + @@ -79,6 +84,7 @@ void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region, if (const Expr *DerefExpr = bugreporter::getDerefExpr(S)) bugreporter::trackExpressionValue(N, DerefExpr, *BR); } + C.addTransition(ReportedState, N); C.emitReport(std::move(BR)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp index 2fab20b199f01..d4a3cfd060aa3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp @@ -15,6 +15,7 @@ REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(LifetimeSourceSet, const MemRegion *) REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMap, SVal, LifetimeSourceSet) REGISTER_SET_WITH_PROGRAMSTATE(DeallocatedSourceSet, const MemRegion *) +REGISTER_SET_WITH_PROGRAMSTATE(ReportedDeadRegions, const MemRegion *) namespace { @@ -86,6 +87,13 @@ bool lifetime_modeling::isDeallocated(ProgramStateRef State, return State->contains<DeallocatedSourceSet>(Region->getBaseRegion()); } +ProgramStateRef lifetime_modeling::markAsReported(ProgramStateRef State, + const MemRegion *Region) { + if (State->contains<ReportedDeadRegions>(Region->getBaseRegion())) + return nullptr; + return State->add<ReportedDeadRegions>(Region->getBaseRegion()); +} + static ProgramStateRef bindSource(ProgramStateRef State, SVal RetVal, const MemRegion *Source) { LifetimeSourceSet::Factory &F = State->get_context<LifetimeSourceSet>(); diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h index 8d6c8e4882d1c..8cfe4526d0d51 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h +++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h @@ -22,6 +22,11 @@ bool isBoundToLifetimeSource(ProgramStateRef State, SVal Val); /// Returns the descriptive name of the memory region or a placeholder if a /// descriptive name cannot be constructed for it. std::string getRegionName(const MemRegion *Reg); + +/// Returns true if \p R is seen the first time. If R was alreay reported +/// before returns false. +ProgramStateRef markAsReported(ProgramStateRef State, const MemRegion *Region); + } // namespace clang::ento::lifetime_modeling #endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_LIFETIMEMODELING_H diff --git a/clang/test/Analysis/dangling-ptr-deref.cpp b/clang/test/Analysis/dangling-ptr-deref.cpp index 7f13c241dadf0..58f4aa7fa7583 100644 --- a/clang/test/Analysis/dangling-ptr-deref.cpp +++ b/clang/test/Analysis/dangling-ptr-deref.cpp @@ -331,3 +331,16 @@ void dangling_through_calls() { // expected-warning@-1 {{Use of 'local' after its lifetime ended}} // expected-note@-2 {{Use of 'local' after its lifetime ended}} } + +// If the same variable is dereferenced multiple times then only +// report for the first dereference. +void multiple_deref() { + int *ptr = nullptr; + { + int a = 5; // expected-note {{'a' initialized to 5}} + ptr = &a; // expected-note {{Value assigned to 'ptr'}} + } // expected-note {{'a' is destroyed here}} + *ptr = 6; // expected-note {{Use of 'a' after its lifetime ended}} + // expected-warning@-1 {{Use of 'a' after its lifetime ended}} + *ptr = 7; +} >From 71cc3708e2858247327d0095384a7e503d427de7 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Mon, 10 Aug 2026 23:50:19 +0200 Subject: [PATCH 2/2] Update doc comment for markAsReported. --- clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h index 8cfe4526d0d51..18f3014cfa6e9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h +++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h @@ -23,8 +23,8 @@ bool isBoundToLifetimeSource(ProgramStateRef State, SVal Val); /// descriptive name cannot be constructed for it. std::string getRegionName(const MemRegion *Reg); -/// Returns true if \p R is seen the first time. If R was alreay reported -/// before returns false. +/// Returns the updated \p State with \p R marked as reported if \p R is seen +/// the first time. Returns nullptr if \p R was already reported. ProgramStateRef markAsReported(ProgramStateRef State, const MemRegion *Region); } // namespace clang::ento::lifetime_modeling _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
