https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/206424
See the comment. >From a4202831efb1c0765fc53b05c76779e5feb273e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Mon, 29 Jun 2026 10:01:52 +0200 Subject: [PATCH] [clang][bytecode] Fix an assertion failure with double deletions See the comment. --- clang/lib/AST/ByteCode/DynamicAllocator.cpp | 7 +++++-- clang/lib/AST/ByteCode/DynamicAllocator.h | 3 +-- clang/lib/AST/ByteCode/Interp.cpp | 2 +- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 +- clang/test/AST/ByteCode/new-delete.cpp | 16 ++++++++++++++++ 5 files changed, 24 insertions(+), 6 deletions(-) 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]; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
