[clang] [LifetimeSafety] Detect use-after-scope through fields in member calls (PR #191731)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 12 11:45:52 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-temporal-safety
Author: NeKon69
<details>
<summary>Changes</summary>
Add `UseFact`s for field origins when calling instance methods.
Fixes #<!-- -->182945
---
Full diff: https://github.com/llvm/llvm-project/pull/191731.diff
3 Files Affected:
- (modified) clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h (+2)
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+14)
- (modified) clang/test/Sema/warn-lifetime-safety.cpp (+42)
``````````diff
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..1864247e53886 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2531,3 +2531,45 @@ 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;
+ }
+};
+
+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;
+ {
+ int num;
+ s.p_ = #
+ }
+ s.bar();
+ s.p_ = &val;
+}
+
+} // namespace method_call_uses_field_origins
``````````
</details>
https://github.com/llvm/llvm-project/pull/191731
More information about the cfe-commits
mailing list