https://github.com/usx95 updated 
https://github.com/llvm/llvm-project/pull/180230

>From cfa69a3ba4ce0d50ac8997d9ef77d8a29a26fc39 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <[email protected]>
Date: Fri, 6 Feb 2026 16:52:59 +0000
Subject: [PATCH] handle unique_ptr::release

---
 .../LifetimeSafety/LifetimeAnnotations.h      |  5 +++++
 .../LifetimeSafety/FactsGenerator.cpp         |  9 +++++++++
 .../LifetimeSafety/LifetimeAnnotations.cpp    | 20 +++++++++++++++++++
 clang/test/Sema/Inputs/lifetime-analysis.h    |  1 +
 clang/test/Sema/warn-lifetime-safety.cpp      | 12 +++++++++++
 5 files changed, 47 insertions(+)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h
index ad3a48667cf2a..d306093cdc8fc 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h
@@ -66,6 +66,11 @@ bool isGslPointerType(QualType QT);
 // Tells whether the type is annotated with [[gsl::Owner]].
 bool isGslOwnerType(QualType QT);
 
+// Returns true if the given method is std::unique_ptr::release().
+// This is treated as a move in lifetime analysis to avoid false-positives
+// when ownership is manually transferred.
+bool isUniquePtrRelease(const CXXMethodDecl *MD);
+
 // Returns true if the given method invalidates iterators or references to
 // container elements (e.g. vector::push_back).
 bool isContainerInvalidationMethod(const CXXMethodDecl &MD);
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index be7886b093bb2..79d926edc8bfd 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -546,6 +546,15 @@ void FactsGenerator::handleMovedArgsInCall(const 
FunctionDecl *FD,
 void FactsGenerator::handleInvalidatingCall(const Expr *Call,
                                             const FunctionDecl *FD,
                                             ArrayRef<const Expr *> Args) {
+  if (const auto *Method = dyn_cast<CXXMethodDecl>(FD);
+      Method && isUniquePtrRelease(Method)) {
+    const Expr *UniquePtrExpr = Args[0];
+    OriginList *MovedOrigins = getOriginsList(*UniquePtrExpr);
+    if (MovedOrigins) {
+      CurrentBlockFacts.push_back(FactMgr.createFact<MovedOriginFact>(
+          UniquePtrExpr, MovedOrigins->getOuterOriginID()));
+    }
+  }
   const auto *MD = dyn_cast<CXXMethodDecl>(FD);
   if (!MD || !MD->isInstance() || !isContainerInvalidationMethod(*MD))
     return;
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp 
b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
index 51196efd3116e..c95c9f088d49e 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeAnnotations.cpp
@@ -255,6 +255,26 @@ template <typename T> static bool 
isRecordWithAttr(QualType Type) {
 bool isGslPointerType(QualType QT) { return isRecordWithAttr<PointerAttr>(QT); 
}
 bool isGslOwnerType(QualType QT) { return isRecordWithAttr<OwnerAttr>(QT); }
 
+static bool isStdUniquePtr(const CXXRecordDecl *RD) {
+  if (!RD || !RD->isInStdNamespace())
+    return false;
+
+  StringRef Name;
+  if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+    Name = CTSD->getSpecializedTemplate()->getName();
+  else if (RD->getIdentifier())
+    Name = RD->getName();
+  else
+    return false;
+
+  return Name == "unique_ptr";
+}
+
+bool isUniquePtrRelease(const CXXMethodDecl *MD) {
+  return MD && MD->getIdentifier() && MD->getName() == "release" &&
+         MD->getNumParams() == 0 && isStdUniquePtr(MD->getParent());
+}
+
 bool isContainerInvalidationMethod(const CXXMethodDecl &MD) {
   const CXXRecordDecl *RD = MD.getParent();
   if (!isInStlNamespace(RD))
diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h 
b/clang/test/Sema/Inputs/lifetime-analysis.h
index 38a28e8dcc49c..f30db1a29b149 100644
--- a/clang/test/Sema/Inputs/lifetime-analysis.h
+++ b/clang/test/Sema/Inputs/lifetime-analysis.h
@@ -129,6 +129,7 @@ struct unique_ptr {
   unique_ptr();
   unique_ptr(unique_ptr<T>&&);
   ~unique_ptr();
+  T* release();
   T &operator*();
   T *get() const;
 };
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 5ad856529ffdf..8f52ff27bc6fd 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -1456,6 +1456,18 @@ void wrong_use_of_move_is_permissive() {
   }         // expected-note {{destroyed here}}
   (void)p;  // expected-note {{later used here}}
 }
+
+void take(int*);
+void test_release_no_uaf() {
+  int* r;
+  // Calling release() marks p as moved from, so its destruction doesn't 
invalidate r.
+  {
+    std::unique_ptr<int> p;
+    r = p.get();        // expected-warning-re {{object whose reference {{.*}} 
may have been moved}}
+    take(p.release());  // expected-note {{potentially moved here}}
+  }                     // expected-note {{destroyed here}}
+  (void)*r;             // expected-note {{later used here}}
+}
 } // namespace strict_warn_on_move
 
 // Implicit this annotations with redecls.

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to