[llvm-branch-commits] [clang] [analyzer] Only bind aggregate lifetime sources in LifetimeModeling for annotated functions (PR #214824)

Benedek Kaibas via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Aug 9 12:58:31 PDT 2026


https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/214824

>From b7cc8da6f3afbd43bf372aca7b898f9e287b3651 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Fri, 7 Aug 2026 15:22:52 +0200
Subject: [PATCH 1/3] [analyzer] Only bind aggregate lifetime sources in
 LifetimeModeling for annotated functions

---
 .../Checkers/LifetimeModeling.cpp             | 21 +++++++++---
 clang/test/Analysis/lifetime-bound.cpp        | 32 +++++++++++++++++++
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
index c2995deb3a6e1..46c8df0d610f3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
@@ -168,6 +168,17 @@ lifetime_modeling::getRegionsFromAggrVal(SVal Val, CheckerContext &C) {
   return {};
 }
 
+static bool isAnnotated(const FunctionDecl *FD) {
+  for (const ParmVarDecl *PVD : FD->parameters()) {
+    if (PVD->hasAttr<LifetimeBoundAttr>())
+      return true;
+  }
+
+  if (lifetimes::implicitObjectParamIsLifetimeBound(FD))
+    return true;
+  return false;
+}
+
 void LifetimeModeling::checkPostCall(const CallEvent &Call,
                                      CheckerContext &C) const {
   ProgramStateRef State = C.getState();
@@ -181,11 +192,13 @@ void LifetimeModeling::checkPostCall(const CallEvent &Call,
     return;
 
   SVal RetVal = Call.getReturnValue();
-  SmallVector<const MemRegion *, 4> AggrRegs =
-      lifetime_modeling::getRegionsFromAggrVal(RetVal, C);
 
-  for (const MemRegion *I : AggrRegs) {
-    State = bindSource(State, RetVal, I);
+  if (isAnnotated(FD)) {
+    SmallVector<const MemRegion *, 4> AggrRegs =
+        lifetime_modeling::getRegionsFromAggrVal(RetVal, C);
+    for (const MemRegion *I : AggrRegs) {
+      State = bindSource(State, RetVal, I);
+    }
   }
 
   for (const ParmVarDecl *PVD : FD->parameters()) {
diff --git a/clang/test/Analysis/lifetime-bound.cpp b/clang/test/Analysis/lifetime-bound.cpp
index 749f264fe53eb..c421ba17325d4 100644
--- a/clang/test/Analysis/lifetime-bound.cpp
+++ b/clang/test/Analysis/lifetime-bound.cpp
@@ -471,3 +471,35 @@ IntPtrArr return_array_field_not_yet_detected() {
   // expected-note at -2    {{Address of stack memory associated with local variable 'z' returned to caller}}
   // expected-warning at -3 {{address of stack memory associated with local variable 'z' returned}}
 }
+
+struct Hold {
+  int *ptr;
+};
+
+Hold retPtr(int &x) {
+  return Hold{&x};
+}
+// Even though there is a lifetime error in the function
+// UseAfterLifetimeEnd should not emit a warning for this
+// case since there is no annotation present in the code.
+// The warning present in the test comes from core.StackAddressEscape
+// checker.
+Hold return_by_val_no_ann() {
+  int num = 4;
+  return retPtr(num);
+  // expected-warning at -1 {{Address of stack memory associated with local variable 'num' returned to caller}}
+  // expected-note at -2    {{Address of stack memory associated with local variable 'num' returned to caller}}
+}
+
+int *unwrap(Hold i [[clang::lifetimebound]]) { return i.ptr; }
+
+// FIXME: If an annotated argument is a by-value struct then
+// Arg.getAsRegion() returns null for CompoundVal/LazyCompoundVal
+// and the dangling pointer will not be detected.
+int *arg_aggregate_lifetimebound() {
+  int local_num = 5;
+  Hold h{&local_num};
+  return unwrap(h);
+  // expected-warning at -1 {{Address of stack memory associated with local variable 'local_num' returned to caller}}
+  // expected-note at -2    {{Address of stack memory associated with local variable 'local_num' returned to caller}}
+}

>From 57cb6096e6d56dc63bf6637589c2af0dd11495e0 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sun, 9 Aug 2026 21:45:58 +0200
Subject: [PATCH 2/3] Refactor hasAnyParamLifetimeAnnotated.

---
 clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
index 46c8df0d610f3..4474fa0b31fa6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
@@ -168,15 +168,13 @@ lifetime_modeling::getRegionsFromAggrVal(SVal Val, CheckerContext &C) {
   return {};
 }
 
-static bool isAnnotated(const FunctionDecl *FD) {
+static bool hasAnyParamLifetimeAnnotated(const FunctionDecl *FD) {
   for (const ParmVarDecl *PVD : FD->parameters()) {
     if (PVD->hasAttr<LifetimeBoundAttr>())
       return true;
   }
 
-  if (lifetimes::implicitObjectParamIsLifetimeBound(FD))
-    return true;
-  return false;
+  return lifetimes::implicitObjectParamIsLifetimeBound(FD);
 }
 
 void LifetimeModeling::checkPostCall(const CallEvent &Call,
@@ -193,7 +191,7 @@ void LifetimeModeling::checkPostCall(const CallEvent &Call,
 
   SVal RetVal = Call.getReturnValue();
 
-  if (isAnnotated(FD)) {
+  if (hasAnyParamLifetimeAnnotated(FD)) {
     SmallVector<const MemRegion *, 4> AggrRegs =
         lifetime_modeling::getRegionsFromAggrVal(RetVal, C);
     for (const MemRegion *I : AggrRegs) {

>From 39785aaf49c98cca4732b86a5214a7e90fde3fb0 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sun, 9 Aug 2026 21:57:44 +0200
Subject: [PATCH 3/3] Use auto for AggrRegs in checkPostCall.

---
 clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
index 4474fa0b31fa6..0cb8b7c1c7c75 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
@@ -192,8 +192,7 @@ void LifetimeModeling::checkPostCall(const CallEvent &Call,
   SVal RetVal = Call.getReturnValue();
 
   if (hasAnyParamLifetimeAnnotated(FD)) {
-    SmallVector<const MemRegion *, 4> AggrRegs =
-        lifetime_modeling::getRegionsFromAggrVal(RetVal, C);
+    auto AggrRegs = lifetime_modeling::getRegionsFromAggrVal(RetVal, C);
     for (const MemRegion *I : AggrRegs) {
       State = bindSource(State, RetVal, I);
     }



More information about the llvm-branch-commits mailing list