[clang] [LifetimeSafety] Track STL algorithm functions that return lifetimebound iterators (PR #179227)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 2 07:16:33 PST 2026
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/179227
>From 4404ad60181b074f999ff473c5fb8b927c7c6213 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Mon, 2 Feb 2026 13:02:13 +0000
Subject: [PATCH] stl algorithms lifetimebound
---
.../LifetimeSafety/LifetimeAnnotations.cpp | 32 +++++++++++++++++--
clang/test/Sema/Inputs/lifetime-analysis.h | 3 ++
.../Sema/warn-lifetime-analysis-nocfg.cpp | 23 +++++++++++++
3 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index be33caf327802..385fb2f05ae2a 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -174,13 +174,41 @@ bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee,
}
bool shouldTrackFirstArgument(const FunctionDecl *FD) {
- if (!FD->getIdentifier() || FD->getNumParams() != 1)
+ if (!FD->getIdentifier() || FD->getNumParams() < 1)
return false;
+ if (!FD->isInStdNamespace())
+ return false;
+ // Track std:: algorithm functions that return an iterator whose lifetime is
+ // bound to the first argument.
+ if (FD->getNumParams() >= 2 && FD->isInStdNamespace() &&
+ isGslPointerType(FD->getReturnType())) {
+ if (llvm::StringSwitch<bool>(FD->getName())
+ .Cases(
+ {
+ "find",
+ "find_if",
+ "find_if_not",
+ "find_first_of",
+ "adjacent_find",
+ "search",
+ "find_end",
+ "lower_bound",
+ "upper_bound",
+ "partition_point",
+ },
+ true)
+ .Default(false))
+ return true;
+ }
const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
- if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
+ if (!RD || !RD->isInStdNamespace())
return false;
if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
return false;
+
+ if (FD->getNumParams() != 1)
+ return false;
+
if (FD->getReturnType()->isPointerType() ||
isGslPointerType(FD->getReturnType())) {
return llvm::StringSwitch<bool>(FD->getName())
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h
index 4f881d463ebcc..27882e68c1524 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -16,6 +16,9 @@ template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T &> { typedef T type; };
template<typename T> struct remove_reference<T &&> { typedef T type; };
+template< class InputIt, class T >
+InputIt find( InputIt first, InputIt last, const T& value );
+
template<typename T>
typename remove_reference<T>::type &&move(T &&t) noexcept;
diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
index c82cf41b07361..a58b446fe4c07 100644
--- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
+++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp
@@ -429,6 +429,29 @@ int *returnPtrToLocalArray() {
return std::begin(a); // TODO
}
+namespace lifetimebound_stl_algorithms {
+
+std::vector<std::string> GetTemporaryString();
+std::vector<std::string_view> GetTemporaryView();
+
+std::string_view test_str_local() {
+ std::vector<std::string> v;
+ return *std::find(v.begin(), // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
+ v.end(), "42");
+}
+std::string_view test_str_temporary() {
+ return *std::find(GetTemporaryString().begin(), // cfg-warning {{address of stack memory is returned later}} cfg-note {{returned here}}
+ GetTemporaryString().end(), "42");
+}
+std::string_view test_view() {
+ std::vector<std::string_view> v;
+ return *std::find(v.begin(), v.end(), "42");
+}
+std::string_view test_view_local() {
+ return *std::find(GetTemporaryView().begin(), GetTemporaryView().end(), "42");
+}
+} // namespace lifetimebound_stl_algorithms
+
struct ptr_wrapper {
std::vector<int>::iterator member;
};
More information about the cfe-commits
mailing list