[clang] [clang][bytecode] Fix stack corruption in builtin delete handler (PR #195741)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 4 23:49:11 PDT 2026
https://github.com/cakgok updated https://github.com/llvm/llvm-project/pull/195741
>From 26357ddf1a56f4fe62567b4ea271f939df23376d Mon Sep 17 00:00:00 2001
From: Cem <cemakgok at gmail.com>
Date: Mon, 4 May 2026 23:13:10 +0300
Subject: [PATCH 1/4] [Clang][ByteCode] Fix stack corruption in builtin delete
handler
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 12 ++++++++++++
clang/test/AST/ByteCode/new-delete.cpp | 10 ++++++++++
2 files changed, 22 insertions(+)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 77ea83605cc16..8fdedd4f783ba 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1633,6 +1633,18 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
const Expr *Source = nullptr;
const Block *BlockToDelete = nullptr;
+ assert(Call->getNumArgs() >= 1);
+ unsigned NumArgs = Call->getNumArgs();
+
+ // The std::nothrow_t argument never put on the stack.
+ if (Call->getArg(NumArgs - 1)->getType()->isNothrowT())
+ --NumArgs;
+
+ // Args are pushed in source order. The trailing sized/aligned delete
+ // operands are above the pointer on the stack.
+ for (unsigned I = NumArgs; I > 1; --I)
+ discard(S.Stk, *S.getContext().classify(Call->getArg(I - 1)));
+
if (S.checkingPotentialConstantExpression()) {
S.Stk.discard<Pointer>();
return false;
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index 4ade50b7c02e4..ac2c2ff4a73c6 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -643,6 +643,9 @@ namespace std {
// both-note {{used to delete a null pointer}} \
// both-note {{delete of pointer '&no_deallocate_nonalloc' that does not point to a heap-allocated object}}
}
+ constexpr void deallocate(void *p, size_t N) {
+ __builtin_operator_delete(p, sizeof(T) * N);
+ }
};
template<typename T, typename ...Args>
constexpr void construct_at(void *p, Args &&...args) { // #construct
@@ -767,6 +770,13 @@ namespace OperatorNewDelete {
// both-note {{in call}}
static_assert((std::allocator<float>().deallocate(std::allocator<float>().allocate(10)), 1) == 1);
+
+ constexpr bool sizedDeallocate() {
+ int *p = std::allocator<int>().allocate(1);
+ std::allocator<int>().deallocate(p, 1);
+ return true;
+ }
+ static_assert(sizedDeallocate());
}
namespace Limits {
>From c3109d979a3c87425f8cd44a37f012d301b3a7df Mon Sep 17 00:00:00 2001
From: cakgok <cemakgok at gmail.com>
Date: Tue, 5 May 2026 09:41:24 +0300
Subject: [PATCH 2/4] Update clang/lib/AST/ByteCode/InterpBuiltin.cpp
Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 8fdedd4f783ba..56d93363226e5 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1643,7 +1643,7 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
// Args are pushed in source order. The trailing sized/aligned delete
// operands are above the pointer on the stack.
for (unsigned I = NumArgs; I > 1; --I)
- discard(S.Stk, *S.getContext().classify(Call->getArg(I - 1)));
+ discard(S.Stk, *S.getContext().classify(Call->getArg(I)));
if (S.checkingPotentialConstantExpression()) {
S.Stk.discard<Pointer>();
>From 3fb4d244575ffa30dbd38eab1d317d78e6f15e92 Mon Sep 17 00:00:00 2001
From: cakgok <cemakgok at gmail.com>
Date: Tue, 5 May 2026 09:41:37 +0300
Subject: [PATCH 3/4] Update clang/lib/AST/ByteCode/InterpBuiltin.cpp
Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 56d93363226e5..fbf037a693ed7 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1642,7 +1642,7 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
// Args are pushed in source order. The trailing sized/aligned delete
// operands are above the pointer on the stack.
- for (unsigned I = NumArgs; I > 1; --I)
+ for (unsigned I = NumArgs - 1; I != 0; --I)
discard(S.Stk, *S.getContext().classify(Call->getArg(I)));
if (S.checkingPotentialConstantExpression()) {
>From 942f0718cc9561d2a1532fd49fc1c4dbb78c404b Mon Sep 17 00:00:00 2001
From: Cem <cemakgok at gmail.com>
Date: Tue, 5 May 2026 09:44:13 +0300
Subject: [PATCH 4/4] fixup! [Clang][ByteCode] Fix stack corruption in builtin
delete handler
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 4 ----
1 file changed, 4 deletions(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index fbf037a693ed7..e398707dc1bd6 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1636,10 +1636,6 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
assert(Call->getNumArgs() >= 1);
unsigned NumArgs = Call->getNumArgs();
- // The std::nothrow_t argument never put on the stack.
- if (Call->getArg(NumArgs - 1)->getType()->isNothrowT())
- --NumArgs;
-
// Args are pushed in source order. The trailing sized/aligned delete
// operands are above the pointer on the stack.
for (unsigned I = NumArgs - 1; I != 0; --I)
More information about the cfe-commits
mailing list