[clang] 2d06fcc - [clang][bytecode] Fix an assertion failure with double deletions (#206424)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 03:47:48 PDT 2026
Author: Timm Baeder
Date: 2026-06-29T12:47:43+02:00
New Revision: 2d06fcc078dd2f382becbf88416a2f6fbe36296a
URL: https://github.com/llvm/llvm-project/commit/2d06fcc078dd2f382becbf88416a2f6fbe36296a
DIFF: https://github.com/llvm/llvm-project/commit/2d06fcc078dd2f382becbf88416a2f6fbe36296a.diff
LOG: [clang][bytecode] Fix an assertion failure with double deletions (#206424)
See the comment.
Added:
Modified:
clang/lib/AST/ByteCode/DynamicAllocator.cpp
clang/lib/AST/ByteCode/DynamicAllocator.h
clang/lib/AST/ByteCode/Interp.cpp
clang/lib/AST/ByteCode/InterpBuiltin.cpp
clang/test/AST/ByteCode/new-delete.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
index a3a0dcd489a76..d70202b92e6e9 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
@@ -110,7 +110,7 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
}
bool DynamicAllocator::deallocate(const Expr *Source,
- const Block *BlockToDelete, InterpState &S) {
+ const Block *BlockToDelete) {
auto It = AllocationSites.find(Source);
if (It == AllocationSites.end())
return false;
@@ -123,7 +123,10 @@ bool DynamicAllocator::deallocate(const Expr *Source,
return BlockToDelete == A.block();
});
- assert(AllocIt != Site.Allocations.end());
+ // The allocation site it fine, but this block doesn't belong to it. Must've
+ // already been deleted.
+ if (AllocIt == Site.Allocations.end())
+ return false;
Block *B = AllocIt->block();
assert(B->isInitialized());
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.h b/clang/lib/AST/ByteCode/DynamicAllocator.h
index ab1058bdf9f22..2336c3f3316c3 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.h
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.h
@@ -80,8 +80,7 @@ class DynamicAllocator final {
/// Deallocate the given source+block combination.
/// Returns \c true if anything has been deallocatd, \c false otherwise.
- bool deallocate(const Expr *Source, const Block *BlockToDelete,
- InterpState &S);
+ bool deallocate(const Expr *Source, const Block *BlockToDelete);
/// Checks whether the allocation done at the given source is an array
/// allocation.
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 2f09c19178f09..0396482517046 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1485,7 +1485,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
if (!RunDestructors(S, OpPC, BlockToDelete))
return false;
- if (!Allocator.deallocate(Source, BlockToDelete, S)) {
+ if (!Allocator.deallocate(Source, BlockToDelete)) {
// Nothing has been deallocated, this must be a double-delete.
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_double_delete);
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index b76f13833da14..73952e032f1eb 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1681,7 +1681,7 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
std::optional<DynamicAllocator::Form> AllocForm =
Allocator.getAllocationForm(Source);
- if (!Allocator.deallocate(Source, BlockToDelete, S)) {
+ if (!Allocator.deallocate(Source, BlockToDelete)) {
// Nothing has been deallocated, this must be a double-delete.
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_double_delete);
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index b9c1e089e6536..24195d77962b8 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -112,6 +112,22 @@ consteval int doubleDelete() { // both-error {{never produces a constant express
static_assert(doubleDelete() == 1); // both-error {{not an integral constant expression}} \
// both-note {{in call to 'doubleDelete()'}}
+template <int N>
+constexpr bool doubleDelete2(const char (&x)[N]) {
+ int *p[N];
+ for (int i = 0; i < N; i++)
+ p[i] = new int(x[i]);
+
+ delete p[0];
+ delete p[0]; // both-note {{delete of pointer that has already been deleted}}
+
+ return true;
+}
+static_assert(doubleDelete2("foo")); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+
+
constexpr int AutoArray() {
auto array = new int[]{0, 1, 2, 3};
int ret = array[3];
More information about the cfe-commits
mailing list