Author: Utkarsh Saxena Date: 2026-02-02T15:39:18Z New Revision: 038591a1c8452099cd5212b2795b325787a6e57b
URL: https://github.com/llvm/llvm-project/commit/038591a1c8452099cd5212b2795b325787a6e57b DIFF: https://github.com/llvm/llvm-project/commit/038591a1c8452099cd5212b2795b325787a6e57b.diff LOG: [LifetimeSafety] Track STL algorithm functions that return lifetimebound iterators (#179227) Enhanced the `shouldTrackFirstArgument` function in `LifetimeAnnotations.cpp` to recognize standard library algorithm functions like `find`, `find_if`, `search`, etc. that return iterators whose lifetimes are bound to their container arguments. This allows the lifetime checker to detect when these iterators outlive their containers. The implementation now: - Checks for standard library algorithm functions that take at least two parameters - Identifies specific functions by name (find, find_if, find_if_not, etc.) - Verifies the return type is a GSL pointer type Added: Modified: clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp clang/test/Sema/Inputs/lifetime-analysis.h clang/test/Sema/warn-lifetime-analysis-nocfg.cpp Removed: ################################################################################ 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; }; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
