[clang] [clang][bytecode] Check if operator delete calls are in the right frame (PR #136141)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 17 07:01:50 PDT 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/136141
This is only permitted in a std::allocator::deallocate frame.
>From 4774ba70d70a33cde681ab8daba7f7429e131ac7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 17 Apr 2025 15:44:49 +0200
Subject: [PATCH] [clang][bytecode] Check if operator delete calls are in the
right frame
This is only permitted in a std::allocator::deallocate frame.
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 35 ++++++++++++++++++++++++
clang/test/AST/ByteCode/new-delete.cpp | 12 ++++++++
2 files changed, 47 insertions(+)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 31d97d9060142..34553301ef630 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1651,6 +1651,41 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
const Expr *Source = nullptr;
const Block *BlockToDelete = nullptr;
+ if (S.checkingPotentialConstantExpression())
+ return false;
+
+ // This is permitted only within a call to std::allocator<T>::deallocate.
+ bool DeallocateFrameFound = false;
+ for (const InterpFrame *F = Frame; F; F = F->Caller) {
+ const Function *Func = F->getFunction();
+ if (!Func)
+ continue;
+ const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr("deallocate"))
+ continue;
+
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
+
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
+ TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
+ DeallocateFrameFound = true;
+ break;
+ }
+ }
+
+ if (!DeallocateFrameFound) {
+ S.FFDiag(Call);
+ return true;
+ }
+
{
const Pointer &Ptr = S.Stk.peek<Pointer>();
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index 5ddd7070f6710..e1b81e9a7963e 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -992,6 +992,18 @@ namespace ZeroSizeSub {
// both-note {{in call to}}
}
+namespace WrongFrame {
+ constexpr int foo() {
+ int *p = nullptr;
+ __builtin_operator_delete(p); // both-note {{subexpression not valid in a constant expression}}
+
+ return 1;
+ }
+ static_assert(foo()); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+}
+
#else
/// Make sure we reject this prior to C++20
constexpr int a() { // both-error {{never produces a constant expression}}
More information about the cfe-commits
mailing list