https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/213779
>From 52d7192d8ce997bac8f6e890e633b095986d1c64 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Tue, 4 Aug 2026 00:11:56 +0200 Subject: [PATCH 1/3] [analyzer] Discard non-live source frames from the current stack --- .../Checkers/LifetimeModeling.cpp | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp index 4b6d76a09575a..3765f4907c9e7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp @@ -52,9 +52,17 @@ 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 (llvm::any_of(C.stackframes(), [&](const StackFrame &Frame) { + if (&Frame != SF) + return false; + return true; + })) + if (SF == CurrentSF || !SF->isParentOf(CurrentSF)) + return true; } return false; } @@ -117,7 +125,27 @@ void LifetimeModeling::checkPostCall(const CallEvent &Call, State = bindSource(State, RetVal, ArgValRegion); } } + /* + auto ViewObj = Call.getReturnValue().getAs<nonloc::LazyCompoundVal>(); + llvm::errs() << ViewObj << "\n"; + RetVal.dump(); + if (!ViewObj) + return; + llvm::errs() << ViewObj; + const MemRegion *LCVRegion = ViewObj->getRegion(); + if (!LCVRegion) + return; + llvm::errs() << LCVRegion << "\n"; + for (const ParmVarDecl *PVD : FD->parameters()) { + if (PVD->hasAttr<LifetimeBoundAttr>()) { + unsigned Idx = PVD->getFunctionScopeIndex(); + SVal Arg = Call.getArgSVal(Idx); + if (const MemRegion *ArgValRegion = Arg.getAsRegion()) + State = bindSource(State, RetVal, ArgValRegion); + } + } + */ const auto *IC = dyn_cast<CXXInstanceCall>(&Call); if (IC && lifetimes::implicitObjectParamIsLifetimeBound(FD)) { if (const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion()) >From 29cb487f72b578fa1f093a775e0a2712b9db611a Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Tue, 4 Aug 2026 13:38:31 +0200 Subject: [PATCH 2/3] Removed commented LCV test implementation. --- .../Checkers/LifetimeModeling.cpp | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp index 3765f4907c9e7..33b36115a6cb0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp @@ -92,6 +92,7 @@ static ProgramStateRef bindSource(ProgramStateRef State, SVal RetVal, LifetimeSourceSet Set = LSet ? *LSet : F.getEmptySet(); Set = F.add(Set, Source); State = State->set<LifetimeBoundMap>(RetVal, Set); + return State; } @@ -125,27 +126,7 @@ void LifetimeModeling::checkPostCall(const CallEvent &Call, State = bindSource(State, RetVal, ArgValRegion); } } - /* - auto ViewObj = Call.getReturnValue().getAs<nonloc::LazyCompoundVal>(); - llvm::errs() << ViewObj << "\n"; - RetVal.dump(); - if (!ViewObj) - return; - llvm::errs() << ViewObj; - const MemRegion *LCVRegion = ViewObj->getRegion(); - if (!LCVRegion) - return; - llvm::errs() << LCVRegion << "\n"; - for (const ParmVarDecl *PVD : FD->parameters()) { - if (PVD->hasAttr<LifetimeBoundAttr>()) { - unsigned Idx = PVD->getFunctionScopeIndex(); - SVal Arg = Call.getArgSVal(Idx); - if (const MemRegion *ArgValRegion = Arg.getAsRegion()) - State = bindSource(State, RetVal, ArgValRegion); - } - } - */ const auto *IC = dyn_cast<CXXInstanceCall>(&Call); if (IC && lifetimes::implicitObjectParamIsLifetimeBound(FD)) { if (const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion()) >From e82f2a099b072ee4e80c4a54ca1c68f6161cf0d1 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Tue, 4 Aug 2026 14:19:15 +0200 Subject: [PATCH 3/3] Add test case. --- .../StaticAnalyzer/Checkers/LifetimeModeling.cpp | 6 ++++-- clang/test/Analysis/lifetime-bound.cpp | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp index 33b36115a6cb0..e9a4ed8559d51 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp @@ -56,13 +56,15 @@ static bool isDanglingStackSource(const MemRegion *Source, // 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 (llvm::any_of(C.stackframes(), [&](const StackFrame &Frame) { if (&Frame != SF) return false; return true; })) - if (SF == CurrentSF || !SF->isParentOf(CurrentSF)) - return true; + */ + 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 ef8ffeb87a8dd..8a1030add8ff7 100644 --- a/clang/test/Analysis/lifetime-bound.cpp +++ b/clang/test/Analysis/lifetime-bound.cpp @@ -378,3 +378,17 @@ CustomStringView dangling_sv() { char s[] = "dangling"; return CustomStringView(s); // expected-warning {{address of stack memory associated with local variable 's' returned}} } + +struct Chained { + Chained &self() [[clang::lifetimebound]] { return *this; } + Chained() { + self(); + self(); // no-warning + } +}; + +void takes_by_value(Chained arg); + +void no_dangling_by_value_argument() { + takes_by_value(Chained()); // no-warning +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
