[clang] [clang][bytecode] Catch placement-new into invalid destination (PR #164804)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 23 04:32:43 PDT 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/164804
We failed to check for null and non-block pointers.
Fixes https://github.com/llvm/llvm-project/issues/152952
>From 720b3460dc2852736bfd192059b935dd3ac548b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Thu, 23 Oct 2025 13:06:54 +0200
Subject: [PATCH] [clang][bytecode] Catch placement-new into invalid
destination
We failed to check for null and non-block pointers.
Fixes https://github.com/llvm/llvm-project/issues/152952
---
clang/lib/AST/ByteCode/Compiler.cpp | 5 +---
clang/lib/AST/ByteCode/Interp.cpp | 7 ++++++
clang/lib/AST/ByteCode/Opcodes.td | 10 ++------
clang/test/AST/ByteCode/placement-new.cpp | 29 +++++++++++++++++++++++
4 files changed, 39 insertions(+), 12 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 6b989276e6d7d..228c6f4b11804 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3600,8 +3600,6 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
if (PlacementDest) {
if (!this->visit(PlacementDest))
return false;
- if (!this->emitStartLifetime(E))
- return false;
if (!this->emitGetLocal(SizeT, ArrayLen, E))
return false;
if (!this->emitCheckNewTypeMismatchArray(SizeT, E, E))
@@ -3741,10 +3739,9 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
if (PlacementDest) {
if (!this->visit(PlacementDest))
return false;
- if (!this->emitStartLifetime(E))
- return false;
if (!this->emitCheckNewTypeMismatch(E, E))
return false;
+
} else {
// Allocate just one element.
if (!this->emitAlloc(Desc, E))
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index a72282caf5e73..939eefc8d2b67 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1903,9 +1903,16 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
if (Ptr.inUnion() && Ptr.getBase().getRecord()->isUnion())
Ptr.activate();
+ if (Ptr.isZero()) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_null)
+ << AK_Construct;
+ return false;
+ }
+
if (!Ptr.isBlockPointer())
return false;
+ startLifetimeRecurse(Ptr);
// Similar to CheckStore(), but with the additional CheckTemporary() call and
// the AccessKinds are different.
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 532c4448e6f40..cc52e06d031a2 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -853,19 +853,13 @@ def Free : Opcode {
let Args = [ArgBool, ArgBool];
}
-def CheckNewTypeMismatch : Opcode {
- let Args = [ArgExpr];
-}
-
-def InvalidNewDeleteExpr : Opcode {
- let Args = [ArgExpr];
-}
-
+def CheckNewTypeMismatch : Opcode { let Args = [ArgExpr]; }
def CheckNewTypeMismatchArray : Opcode {
let Types = [IntegerTypeClass];
let Args = [ArgExpr];
let HasGroup = 1;
}
+def InvalidNewDeleteExpr : Opcode { let Args = [ArgExpr]; }
def IsConstantContext: Opcode;
def CheckAllocations : Opcode;
diff --git a/clang/test/AST/ByteCode/placement-new.cpp b/clang/test/AST/ByteCode/placement-new.cpp
index b587cd6eaf89c..1c015da7be54f 100644
--- a/clang/test/AST/ByteCode/placement-new.cpp
+++ b/clang/test/AST/ByteCode/placement-new.cpp
@@ -494,3 +494,32 @@ constexpr int modify_const_variable() {
}
static_assert(modify_const_variable()); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
+
+constexpr int nullDest() {
+ new (nullptr) int{12}; // both-note {{construction of dereferenced null pointer}}
+ return 0;
+}
+static_assert(nullDest() == 0); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+constexpr int nullArrayDest() {
+ new (nullptr) int{12}; // both-note {{construction of dereferenced null pointer}}
+ return 0;
+}
+static_assert(nullArrayDest() == 0); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+constexpr int intDest() {
+ new ((void*)2) int{3}; // both-note {{cast that performs the conversions of a reinterpret_cast}}
+ return 0;
+}
+static_assert(intDest() == 0); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+constexpr int intDestArray() {
+ new ((void*)2) int[4]; // both-note {{cast that performs the conversions of a reinterpret_cast}}
+ return 0;
+}
+static_assert(intDestArray() == 0); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
More information about the cfe-commits
mailing list