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 1/5] [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_ = # // 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_ = # + } + 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
