[clang] [clang][bytecode] Check downcasts for the correct type (PR #140689)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Tue May 20 01:19:10 PDT 2025
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/140689
>From f1fced9ca8e23ccc4092c2359f9d385fbbaad58f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 20 May 2025 09:06:15 +0200
Subject: [PATCH] [clang][bytecode] Check downcasts for the correct type
In multiple inheritance/diamond scenarios, we might arrive at
the wrong type.
---
clang/lib/AST/ByteCode/Compiler.cpp | 9 ++++++---
clang/lib/AST/ByteCode/Interp.h | 16 +++++++++++++++-
clang/lib/AST/ByteCode/Opcodes.td | 2 +-
clang/test/AST/ByteCode/records.cpp | 12 ++++++++++++
4 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index aa8f009f58bb9..fd2f25d2476c5 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -296,12 +296,15 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_BaseToDerived: {
if (!this->delegate(SubExpr))
return false;
-
unsigned DerivedOffset =
collectBaseOffset(SubExpr->getType(), CE->getType());
- return this->emitGetPtrDerivedPop(
- DerivedOffset, /*NullOK=*/CE->getType()->isPointerType(), CE);
+ const Type *TargetType = CE->getType().getTypePtr();
+ if (TargetType->isPointerOrReferenceType())
+ TargetType = TargetType->getPointeeType().getTypePtr();
+ return this->emitGetPtrDerivedPop(DerivedOffset,
+ /*NullOK=*/CE->getType()->isPointerType(),
+ TargetType, CE);
}
case CK_FloatingCast: {
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 9f1a6302eb856..2a60606b6c3e3 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1643,7 +1643,7 @@ inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
}
inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
- bool NullOK) {
+ bool NullOK, const Type *TargetType) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
return false;
@@ -1661,6 +1661,20 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
if (!CheckDowncast(S, OpPC, Ptr, Off))
return false;
+ const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
+ assert(TargetRecord);
+
+ if (TargetRecord->getDecl()
+ ->getTypeForDecl()
+ ->getAsCXXRecordDecl()
+ ->getCanonicalDecl() !=
+ TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
+ QualType MostDerivedType = Ptr.getDeclDesc()->getType();
+ S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
+ << MostDerivedType << QualType(TargetType, 0);
+ return false;
+ }
+
S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
return true;
}
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 9dddcced8ca38..c8db8da113bd4 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -325,7 +325,7 @@ def GetMemberPtrBasePop : Opcode {
def FinishInitPop : Opcode;
def FinishInit : Opcode;
-def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool]; }
+def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; }
// [Pointer] -> [Pointer]
def GetPtrVirtBasePop : Opcode {
diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index c2fe3d9007480..9361d6ddeda70 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -1830,3 +1830,15 @@ namespace NullDtor {
static_assert(foo() == 10, ""); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}
+
+namespace DiamondDowncast {
+ struct Top {};
+ struct Middle1 : Top {};
+ struct Middle2 : Top {};
+ struct Bottom : Middle1, Middle2 {};
+
+ constexpr Bottom bottom;
+ constexpr Top &top1 = (Middle1&)bottom;
+ constexpr Middle2 &fail = (Middle2&)top1; // both-error {{must be initialized by a constant expression}} \
+ // both-note {{cannot cast object of dynamic type 'const Bottom' to type 'Middle2'}}
+}
More information about the cfe-commits
mailing list