llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Benedek Kaibas (benedekaibas)

<details>
<summary>Changes</summary>

If the same variable is dereferenced multiple times then the `DanglingPtrDeref` 
checker should only emit a single wanring for it instead of multiple ones. If 
there are multiple variables dereferenced then for each variable there should 
be one warning emitted. For that reason I have implemented the `markAsReported` 
function which returns the updated state with the memory region of the given 
variable marked as reported if the memory region is seen for the first time.

---
Full diff: https://github.com/llvm/llvm-project/pull/215409.diff


4 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp (+6) 
- (modified) clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp (+8) 
- (modified) clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h (+5) 
- (modified) clang/test/Analysis/dangling-ptr-deref.cpp (+13) 


``````````diff
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..18f3014cfa6e9 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 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
 
 #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;
+}

``````````

</details>


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

Reply via email to