[clang] [LifetimeSafety] Avoid assert on variadic placement new (PR #199588)
Zeyi Xu via cfe-commits
cfe-commits at lists.llvm.org
Tue May 26 22:28:17 PDT 2026
https://github.com/zeyi2 updated https://github.com/llvm/llvm-project/pull/199588
>From 6098a2aa97e913b54675f6257e159d42ac1dcffc Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Tue, 26 May 2026 09:02:27 +0800
Subject: [PATCH 1/2] [LifetimeSafety] Avoid assert on variadic placement new
---
.../LifetimeSafety/FactsGenerator.cpp | 45 ++++++++++---------
clang/test/Sema/warn-lifetime-safety.cpp | 11 +++++
2 files changed, 34 insertions(+), 22 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 8a7a4b79a1584..fa5a1aa4a7903 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -640,28 +640,29 @@ void FactsGenerator::VisitCXXNewExpr(const CXXNewExpr *NE) {
// And that the placement parameter num is 1,
// that is to mostly limit to standard library placement new.
if (NE->getNumPlacementArgs() == 1) {
- if (const auto *Arg = NE->getOperatorNew()
- ->getParamDecl(1)
- ->getType()
- ->getAs<PointerType>();
- Arg && Arg->isVoidPointerType()) {
- // Use the placement argument before the implicit conversion to void*, so
- // inner origins are still available.
- const Expr *PlacementArg = NE->getPlacementArg(0);
- if (const auto *ICE = dyn_cast<ImplicitCastExpr>(PlacementArg);
- ICE && ICE->getCastKind() == CK_BitCast &&
- PlacementArg->getType()->isVoidPointerType())
- PlacementArg = ICE->getSubExpr();
- OriginList *PlacementList = getOriginsList(*PlacementArg);
- // FIXME: General placement arguments need separate handling to overwrite
- // the right origins.
-
- // The pointer returned by placement new comes from the placement
- // argument.
- if (PlacementList)
- CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
- NewList->getOuterOriginID(), PlacementList->getOuterOriginID(),
- true));
+ const FunctionDecl *OperatorNew = NE->getOperatorNew();
+ if (OperatorNew->getNumParams() > 1) {
+ if (const auto *Arg =
+ OperatorNew->getParamDecl(1)->getType()->getAs<PointerType>();
+ Arg && Arg->isVoidPointerType()) {
+ // Use the placement argument before the implicit conversion to void*,
+ // so inner origins are still available.
+ const Expr *PlacementArg = NE->getPlacementArg(0);
+ if (const auto *ICE = dyn_cast<ImplicitCastExpr>(PlacementArg);
+ ICE && ICE->getCastKind() == CK_BitCast &&
+ PlacementArg->getType()->isVoidPointerType())
+ PlacementArg = ICE->getSubExpr();
+ OriginList *PlacementList = getOriginsList(*PlacementArg);
+ // FIXME: General placement arguments need separate handling to
+ // overwrite the right origins.
+
+ // The pointer returned by placement new comes from the placement
+ // argument.
+ if (PlacementList)
+ CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
+ NewList->getOuterOriginID(), PlacementList->getOuterOriginID(),
+ true));
+ }
}
} else {
const Loan *L = createLoan(FactMgr, NE);
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 70ec968dfd5c1..4bb7eb1e49437 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2982,6 +2982,17 @@ void placement_new_heap_then_delete_use_after_free() {
(void)*p; // expected-note {{later used here}}
}
+struct PlacementArg {};
+
+struct VariadicPlacementNew {
+ void *operator new(decltype(sizeof(0)), ...);
+};
+
+void variadic_placement_new() {
+ PlacementArg arg;
+ (void)new (arg) VariadicPlacementNew;
+}
+
int* foo(int* x [[clang::lifetimebound]], int* y [[clang::lifetimebound]]);
void placement_new_delete_result_of_lifetimebound_call() {
>From d768bf23407fac57626e33b94886b7b2a7a460fd Mon Sep 17 00:00:00 2001
From: Zeyi Xu <mitchell.xu2 at gmail.com>
Date: Wed, 27 May 2026 13:27:51 +0800
Subject: [PATCH 2/2] ~
---
clang/test/Sema/warn-lifetime-safety.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 4bb7eb1e49437..bba18248a2af3 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2985,7 +2985,7 @@ void placement_new_heap_then_delete_use_after_free() {
struct PlacementArg {};
struct VariadicPlacementNew {
- void *operator new(decltype(sizeof(0)), ...);
+ void *operator new(std::size_t, ...);
};
void variadic_placement_new() {
More information about the cfe-commits
mailing list