[clang] [LifetimeSafety] Fix off-by-one crash in `lifetime_capture_by` argument indexing (PR #227231)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 29 02:13:49 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-temporal-safety
@llvm/pr-subscribers-clang
Author: Utkarsh Saxena (usx95)
<details>
<summary>Changes</summary>
Fixes an off-by-one crash in the lifetime_capture_by attribute handling. The CapturingArgIdx is already an index into the full Args array, but the code was incorrectly creating a CallArgs array (dropping the first argument for instance methods) and then indexing into it with CapturingArgIdx, causing incorrect argument access and potential out-of-bounds crashes.
---
Full diff: https://github.com/llvm/llvm-project/pull/227231.diff
2 Files Affected:
- (modified) clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp (+6-5)
- (modified) clang/test/Sema/LifetimeSafety/safety.cpp (+23)
``````````diff
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 292e3279233bb..a6726c46f5347 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -1044,11 +1044,12 @@ void FactsGenerator::handleLifetimeCaptureBy(const FunctionDecl *FD,
CapturingArgIdx == LifetimeCaptureByAttr::Unknown ||
CapturingArgIdx == LifetimeCaptureByAttr::Invalid)
continue;
- ArrayRef<const Expr *> CallArgs = IsInstance ? Args.drop_front() : Args;
- const Expr *CapturedByArg =
- (CapturingArgIdx == LifetimeCaptureByAttr::This)
- ? Args[0]
- : CallArgs[CapturingArgIdx];
+ // FIXME: Diagnose bad CapturingArgIdx.
+ if (CapturingArgIdx != LifetimeCaptureByAttr::This &&
+ (CapturingArgIdx < 0 ||
+ static_cast<size_t>(CapturingArgIdx) >= Args.size()))
+ continue;
+ const Expr *CapturedByArg = Args[CapturingArgIdx];
assert(CapturedByArg && "Capturer expression must be valid");
OriginList *Dest = readValue(CapturedByArg);
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index bf49e86577678..fb91fb30713db 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -4076,6 +4076,29 @@ void capturing_multiple_locals() {
use(v); // expected-note 2 {{later used here}}
}
+namespace off_by_one_crash {
+struct Item {
+ const int* ptr;
+};
+
+struct Container {
+ const Item* saved;
+};
+
+struct Helper {
+ void AddItem(const Item& item [[clang::lifetime_capture_by(c)]],
+ Container& c) const;
+ void Populate() const {
+ Container c{};
+ {
+ Item item;
+ AddItem(item, c); // expected-warning {{local variable 'item' does not live long enough}}
+ } // expected-note {{local variable 'item' is destroyed here}}
+ use(c); // expected-note {{later used here}}
+ }
+};
+} // namespace off_by_one_crash
+
struct [[gsl::Pointer()]] PtrWithInt { int x; };
PtrWithInt f() {
return PtrWithInt{10};
``````````
</details>
https://github.com/llvm/llvm-project/pull/227231
More information about the cfe-commits
mailing list