https://github.com/NeKon69 updated 
https://github.com/llvm/llvm-project/pull/191731

>From 382e365ec09c88eb36fbd83874a5923295fe9b95 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Sun, 12 Apr 2026 21:24:43 +0300
Subject: [PATCH 01/10] [LifetimeSafety] implement basic fix, add tests

---
 .../Analyses/LifetimeSafety/FactsGenerator.h  |  2 ++
 .../LifetimeSafety/FactsGenerator.cpp         | 14 ++++++++
 clang/test/Sema/warn-lifetime-safety.cpp      | 32 +++++++++++++++++++
 3 files changed, 48 insertions(+)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index 2dbadb27981a7..a3b759c473a16 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -74,6 +74,8 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
 
   void handleExitBlock();
 
+  void handleImplicitObjectFieldUses(const Expr *Call, const FunctionDecl *FD);
+
   void handleGSLPointerConstruction(const CXXConstructExpr *CCE);
 
   /// Detects arguments passed to rvalue reference parameters and creates
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 82b890b57817e..eaf26cb49aba5 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -723,6 +723,19 @@ void FactsGenerator::handleInvalidatingCall(const Expr 
*Call,
         ThisList->getOuterOriginID(), Call));
 }
 
+void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call,
+                                                   const FunctionDecl *FD) {
+  const auto *MD = dyn_cast<CXXMethodDecl>(FD);
+  if (!MD || !MD->isInstance())
+    return;
+
+  for (const auto *Field : MD->getParent()->fields()) {
+    OriginList *FieldList = getOriginsList(*Field);
+    if (FieldList)
+      CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(Call, 
FieldList));
+  }
+}
+
 void FactsGenerator::handleFunctionCall(const Expr *Call,
                                         const FunctionDecl *FD,
                                         ArrayRef<const Expr *> Args,
@@ -737,6 +750,7 @@ void FactsGenerator::handleFunctionCall(const Expr *Call,
     handleUse(Arg);
   handleInvalidatingCall(Call, FD, Args);
   handleMovedArgsInCall(FD, Args);
+  handleImplicitObjectFieldUses(Call, FD);
   if (!CallList)
     return;
   auto IsArgLifetimeBound = [FD](unsigned I) -> bool {
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 77d8e3370676d..63a82680955ac 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2531,3 +2531,35 @@ int *noreturn_dead_nested(bool cond, bool cond2, int 
*num) {
 }
 
 } // namespace conditional_operator_control_flow
+
+namespace method_call_uses_field_origins {
+// https://github.com/llvm/llvm-project/issues/182945
+
+int val;
+
+struct S {
+public:
+  int* p_;
+  void bar();
+  void foo() {
+    {
+      int num;
+      this->p_ = &num; // expected-warning {{object whose reference is 
captured does not live long enough}}
+    }                  // expected-note {{destroyed here}}
+    bar();             // expected-note {{later used here}}
+    this->p_ = &val;
+  }
+};
+
+// FIXME: False-positive: the analysis tracks a, but not that it belongs to s1.
+void foo() {
+  S s;
+  {
+    int num;
+    s.p_ = &num;
+  }
+  s.bar();
+  s.p_ = &val;
+}
+
+} // namespace method_call_uses_field_origins

>From ae721e42f219fe61c85493c7699673b099838145 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Sun, 12 Apr 2026 21:41:44 +0300
Subject: [PATCH 02/10] add a new test

---
 clang/test/Sema/warn-lifetime-safety.cpp | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 63a82680955ac..1864247e53886 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2551,6 +2551,16 @@ struct S {
   }
 };
 
+struct T {
+public:
+  std::string_view v;
+  void bar();
+  void foo() {
+    v = std::string("tmp"); // expected-warning {{object whose reference is 
captured does not live long enough}} expected-note {{destroyed here}}
+    bar();                  // expected-note {{later used here}}
+  }
+};
+
 // FIXME: False-positive: the analysis tracks a, but not that it belongs to s1.
 void foo() {
   S s;

>From 69897653f520b9c26843ccf8aa51684420f32548 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Sun, 12 Apr 2026 22:23:49 +0300
Subject: [PATCH 03/10] update failed test

---
 clang/unittests/Analysis/LifetimeSafetyTest.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp 
b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index 6cf65dd64ef83..879df0d147267 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -1408,7 +1408,6 @@ TEST_F(LifetimeAnalysisTest, TrivialClassDestructorsUAF) {
     }
   )");
   EXPECT_THAT(Origin("ptr"), HasLoansTo({"s"}, "p1"));
-  EXPECT_THAT(Origins({"ptr"}), MustBeLiveAt("p1"));
 }
 
 TEST_F(LifetimeAnalysisTest, SimpleReturnStackAddress) {

>From 806694352ec90e0785a10fe9254adf20f86b640b Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Mon, 13 Apr 2026 09:13:37 +0300
Subject: [PATCH 04/10] update test

---
 clang/test/Sema/warn-lifetime-safety.cpp | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index 1864247e53886..ef1911ede59ad 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2533,9 +2533,8 @@ int *noreturn_dead_nested(bool cond, bool cond2, int 
*num) {
 } // namespace conditional_operator_control_flow
 
 namespace method_call_uses_field_origins {
-// https://github.com/llvm/llvm-project/issues/182945
-
 int val;
+std::string GLOBAL{"123"};
 
 struct S {
 public:
@@ -2559,9 +2558,16 @@ struct T {
     v = std::string("tmp"); // expected-warning {{object whose reference is 
captured does not live long enough}} expected-note {{destroyed here}}
     bar();                  // expected-note {{later used here}}
   }
+  void baz(){
+    std::vector<std::string> vec = {"42"};
+    v = vec[0];         // expected-warning {{object whose reference is 
captured is later invalidated}}
+    vec.push_back("1"); // expected-note {{invalidated here}}
+    bar();              // expected-note {{later used here}}
+    v = GLOBAL;
+  }
 };
 
-// FIXME: False-positive: the analysis tracks a, but not that it belongs to s1.
+// FIXME: False-negative: the analysis tracks `p_`, but not that it belongs to 
s1.
 void foo() {
   S s;
   {

>From 91ce6ffbe52ae0a41c28629e40dc33b0efe2116a Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Mon, 13 Apr 2026 09:17:01 +0300
Subject: [PATCH 05/10] add a comment

---
 .../clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h     | 2 ++
 1 file changed, 2 insertions(+)

diff --git 
a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h 
b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index a3b759c473a16..000f0dde2217d 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -74,6 +74,8 @@ class FactsGenerator : public 
ConstStmtVisitor<FactsGenerator> {
 
   void handleExitBlock();
 
+  /// Mark all fields of the implicit object as used for an instance method
+  /// call, since the callee may access any part of the object.
   void handleImplicitObjectFieldUses(const Expr *Call, const FunctionDecl *FD);
 
   void handleGSLPointerConstruction(const CXXConstructExpr *CCE);

>From 13dc1c4a8d9d71874dd38197e1bec536166ccfa7 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Mon, 13 Apr 2026 11:15:25 +0300
Subject: [PATCH 06/10] address review comments

---
 .../LifetimeSafety/FactsGenerator.cpp         |  6 ++---
 .../warn-lifetime-safety-invalidations.cpp    | 15 +++++++++++
 clang/test/Sema/warn-lifetime-safety.cpp      | 25 +++++++++----------
 3 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index eaf26cb49aba5..1fbee2f3598d9 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -729,11 +729,9 @@ void FactsGenerator::handleImplicitObjectFieldUses(const 
Expr *Call,
   if (!MD || !MD->isInstance())
     return;
 
-  for (const auto *Field : MD->getParent()->fields()) {
-    OriginList *FieldList = getOriginsList(*Field);
-    if (FieldList)
+  for (const auto *Field : MD->getParent()->fields())
+    if (auto *FieldList = getOriginsList(*Field))
       CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(Call, 
FieldList));
-  }
 }
 
 void FactsGenerator::handleFunctionCall(const Expr *Call,
diff --git a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp 
b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
index c7f920c03736a..5a77ac97d16b1 100644
--- a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp
@@ -512,3 +512,18 @@ void ref_capture_reassigned_to_safe() {
   lambda();  // should not warn
 }
 } // namespace lambda_capture_invalidation
+
+namespace method_call_uses_field_invalidation {
+
+struct S {
+  std::string_view v;
+  void bar();
+  void baz(){
+    std::vector<std::string> vec = {"42"};
+    v = vec[0];         // expected-warning {{object whose reference is 
captured is later invalidated}}
+    vec.push_back("1"); // expected-note {{invalidated here}}
+    bar();              // expected-note {{later used here}}
+    v = nullptr;
+  }
+};
+} // namespace method_call_uses_field_invalidation
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp 
b/clang/test/Sema/warn-lifetime-safety.cpp
index ef1911ede59ad..4e562d6a7c06c 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2533,11 +2533,10 @@ int *noreturn_dead_nested(bool cond, bool cond2, int 
*num) {
 } // namespace conditional_operator_control_flow
 
 namespace method_call_uses_field_origins {
-int val;
-std::string GLOBAL{"123"};
+int GLOBAL_INT;
+std::string GLOBAL_STRING{"123"};
 
 struct S {
-public:
   int* p_;
   void bar();
   void foo() {
@@ -2546,25 +2545,25 @@ struct S {
       this->p_ = &num; // expected-warning {{object whose reference is 
captured does not live long enough}}
     }                  // expected-note {{destroyed here}}
     bar();             // expected-note {{later used here}}
-    this->p_ = &val;
+    this->p_ = &GLOBAL_INT;
+  }
+  void baz() {
+    {
+      int num;
+      this->p_ = &num;
+    }
+    this->p_ = &GLOBAL_INT;
+    bar();
   }
 };
 
 struct T {
-public:
   std::string_view v;
   void bar();
   void foo() {
     v = std::string("tmp"); // expected-warning {{object whose reference is 
captured does not live long enough}} expected-note {{destroyed here}}
     bar();                  // expected-note {{later used here}}
   }
-  void baz(){
-    std::vector<std::string> vec = {"42"};
-    v = vec[0];         // expected-warning {{object whose reference is 
captured is later invalidated}}
-    vec.push_back("1"); // expected-note {{invalidated here}}
-    bar();              // expected-note {{later used here}}
-    v = GLOBAL;
-  }
 };
 
 // FIXME: False-negative: the analysis tracks `p_`, but not that it belongs to 
s1.
@@ -2575,7 +2574,7 @@ void foo() {
     s.p_ = &num;
   }
   s.bar();
-  s.p_ = &val;
+  s.p_ = &GLOBAL_INT;
 }
 
 } // namespace method_call_uses_field_origins

>From 8d623bb7c8a74a5e08b02f68987e3ab86ba4a7e8 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Mon, 13 Apr 2026 14:41:06 +0300
Subject: [PATCH 07/10] use base fields too (doesn't work currently)

---
 .../LifetimeSafety/FactsGenerator.cpp         | 23 ++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 1fbee2f3598d9..3e4807c5b2e48 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -729,9 +729,26 @@ void FactsGenerator::handleImplicitObjectFieldUses(const 
Expr *Call,
   if (!MD || !MD->isInstance())
     return;
 
-  for (const auto *Field : MD->getParent()->fields())
-    if (auto *FieldList = getOriginsList(*Field))
-      CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(Call, 
FieldList));
+  const auto *ClassDecl = MD->getParent()->getDefinition();
+  if (!ClassDecl)
+    return;
+
+  const auto UseFields =
+      [&](const CXXRecordDecl *RD) {
+        for (const auto *Field : RD->fields())
+          if (auto *FieldList = getOriginsList(*Field)) {
+            CurrentBlockFacts.push_back(
+                FactMgr.createFact<UseFact>(Call, FieldList));
+            Field->dumpColor();
+          }
+      };
+
+  UseFields(ClassDecl);
+
+  ClassDecl->forallBases([&](const CXXRecordDecl *Base) {
+    UseFields(Base);
+    return true;
+  });
 }
 
 void FactsGenerator::handleFunctionCall(const Expr *Call,

>From d6e79449ea987347c94e8b86f44dad2b703bd7c1 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Mon, 13 Apr 2026 14:45:35 +0300
Subject: [PATCH 08/10] cleanup lambda

---
 .../Analysis/LifetimeSafety/FactsGenerator.cpp    | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 3e4807c5b2e48..71614407b8558 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -733,15 +733,12 @@ void FactsGenerator::handleImplicitObjectFieldUses(const 
Expr *Call,
   if (!ClassDecl)
     return;
 
-  const auto UseFields =
-      [&](const CXXRecordDecl *RD) {
-        for (const auto *Field : RD->fields())
-          if (auto *FieldList = getOriginsList(*Field)) {
-            CurrentBlockFacts.push_back(
-                FactMgr.createFact<UseFact>(Call, FieldList));
-            Field->dumpColor();
-          }
-      };
+  const auto UseFields = [&](const CXXRecordDecl *RD) {
+    for (const auto *Field : RD->fields())
+      if (auto *FieldList = getOriginsList(*Field))
+        CurrentBlockFacts.push_back(
+            FactMgr.createFact<UseFact>(Call, FieldList));
+  };
 
   UseFields(ClassDecl);
 

>From 8f3bc9471798647829e51af5bc41d78156f53e1d Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Mon, 13 Apr 2026 15:52:08 +0300
Subject: [PATCH 09/10] check if implicit object is `this`

---
 clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp 
b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 71614407b8558..460783529e4dd 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -734,6 +734,15 @@ void FactsGenerator::handleImplicitObjectFieldUses(const 
Expr *Call,
     return;
 
   const auto UseFields = [&](const CXXRecordDecl *RD) {
+    const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call);
+    if (!MemberCall)
+      return;
+
+    const auto *This =
+        dyn_cast_or_null<CXXThisExpr>(MemberCall->getImplicitObjectArgument());
+    if (!This)
+      return;
+
     for (const auto *Field : RD->fields())
       if (auto *FieldList = getOriginsList(*Field))
         CurrentBlockFacts.push_back(

>From 26737cbb74eedab78e24dfa2d56ed20762c83857 Mon Sep 17 00:00:00 2001
From: NeKon69 <[email protected]>
Date: Mon, 13 Apr 2026 16:00:18 +0300
Subject: [PATCH 10/10] update test

---
 clang/unittests/Analysis/LifetimeSafetyTest.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp 
b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index 879df0d147267..6cf65dd64ef83 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -1408,6 +1408,7 @@ TEST_F(LifetimeAnalysisTest, TrivialClassDestructorsUAF) {
     }
   )");
   EXPECT_THAT(Origin("ptr"), HasLoansTo({"s"}, "p1"));
+  EXPECT_THAT(Origins({"ptr"}), MustBeLiveAt("p1"));
 }
 
 TEST_F(LifetimeAnalysisTest, SimpleReturnStackAddress) {

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

Reply via email to