Author: Benedek Kaibas
Date: 2026-08-05T16:09:55+02:00
New Revision: af757e5538a8fdb0df6c9dc774cf176f0117cb12

URL: 
https://github.com/llvm/llvm-project/commit/af757e5538a8fdb0df6c9dc774cf176f0117cb12
DIFF: 
https://github.com/llvm/llvm-project/commit/af757e5538a8fdb0df6c9dc774cf176f0117cb12.diff

LOG: [analyzer] Discard stack frames that are not on the current live stack 
(#213779)

When a source's stack frame is not live on the current stack the
`UseAfterLifetimeEnd` checker emitted a false positive. Such sources
outlive the returned value, so they are not dangling stack sources. This
led to multiple false positives when I ran the `UseAfterLifetimeEnd`
checker on the LLVM project.

---------

Co-authored-by: isuckatcs <[email protected]>

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
    clang/test/Analysis/lifetime-bound.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp 
b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
index 7b9fb7acb21ab..2fab20b199f01 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
@@ -52,9 +52,14 @@ static bool isDanglingStackSource(const MemRegion *Source,
         })) {
       return false;
     }
-
-    if (SF == CurrentSF || !SF->isParentOf(CurrentSF))
-      return true;
+    // Only a source whose frame is still live on the current stack can
+    // dangle. If that frame is not on the stack then the source outlives
+    // the returned value. The source is still alive when the returned value
+    // is used, so it does not dangle.
+    if (is_contained(make_pointer_range(C.stackframes()), SF)) {
+      if (SF == CurrentSF || !SF->isParentOf(CurrentSF))
+        return true;
+    }
   }
   return false;
 }

diff  --git a/clang/test/Analysis/lifetime-bound.cpp 
b/clang/test/Analysis/lifetime-bound.cpp
index 06c6ee9a4dd3a..d29c37f639993 100644
--- a/clang/test/Analysis/lifetime-bound.cpp
+++ b/clang/test/Analysis/lifetime-bound.cpp
@@ -391,3 +391,22 @@ CustomStringView dangling_sv() {
   char s[] = "dangling";
   return CustomStringView(s); // expected-warning {{address of stack memory 
associated with local variable 's' returned}} 
 }
+
+// `self()` is annotated [[clang::lifetimebound]], so its return is bound to
+// *this. The BoundToSelf instance is built as a by-value argument temporary,
+// so its frame is not live on the stack when self() returns. 
+struct BoundToSelf {
+  BoundToSelf &self() [[clang::lifetimebound]] { return *this; } // no-warning
+  BoundToSelf() {
+    self();
+    self();
+  }
+};
+
+void takes_by_value(BoundToSelf arg);
+
+void no_dangling_by_value_argument() {
+  // The BoundToSelf temporary's frame is not live on the stack when `self()` 
returns.
+  // The returned reference does not dangle.
+  takes_by_value(BoundToSelf());
+}


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

Reply via email to