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
