https://github.com/cakgok created
https://github.com/llvm/llvm-project/pull/195741
**Problem:**
A crash happens with std::allocator triggered sized/aligned delete operations
with new constant evaluator.
`interp__builtin_operator_delete` currently consumes the top of the interpreter
stack as a `Pointer`.
This is correct for unsized delete:
```cpp
__builtin_operator_delete(p);
```
but not for sized/aligned delete reached through
`std::allocator<T>::deallocate`:
```cpp
__builtin_operator_delete(p, size);
__builtin_operator_delete(p, size, align);
```
In those cases, the trailing operands are pushed after the pointer, so the
stack top is the size/alignment operand rather than the pointer. The delete
builtin handler must discard those trailing operands first.
Tested versions: 22.1.3, Trunk (x86_64-pc-linux-gnu)
**How to reproduce:**
```cpp
#include <vector>
std::vector<int> v(1);
```
For a non STL container reproduction
```cpp
typedef __SIZE_TYPE__ size_t;
namespace std {
template <class T>
struct allocator {
constexpr T *allocate(size_t n) {
return static_cast<T *>(__builtin_operator_new(n * sizeof(T)));
}
constexpr void deallocate(T *p, size_t n) {
__builtin_operator_delete(p, n * sizeof(T));
}
};
}
constexpr bool f() {
int *p = std::allocator<int>().allocate(1);
std::allocator<int>().deallocate(p, 1);
return true;
}
static_assert(f());
```
Crashes with:
```bash
clang++ -std=c++20 -fexperimental-new-constant-interpreter test.cpp
```
**Fix:**
**Testing:**
* Added a regression test.
* The regression goes through `std::allocator<T>::deallocate` rather than
calling
`__builtin_operator_delete` directly. Because a direct user call is caught
before the deallocation logic that consumes the pointer operand.
Assisted-by: gemini-cli
@tbaederr
>From 26357ddf1a56f4fe62567b4ea271f939df23376d Mon Sep 17 00:00:00 2001
From: Cem <[email protected]>
Date: Mon, 4 May 2026 23:13:10 +0300
Subject: [PATCH] [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 {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits