Skip to content

Commit d013556

Browse files
authored
[clang][bytecode] Check downcasts for the correct type (llvm#140689)
In multiple inheritance/diamond scenarios, we might arrive at the wrong type.
1 parent 2fb6ff4 commit d013556

File tree

4 files changed

+34
-5
lines changed

4 files changed

+34
-5
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,15 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
296296
case CK_BaseToDerived: {
297297
if (!this->delegate(SubExpr))
298298
return false;
299-
300299
unsigned DerivedOffset =
301300
collectBaseOffset(SubExpr->getType(), CE->getType());
302301

303-
return this->emitGetPtrDerivedPop(
304-
DerivedOffset, /*NullOK=*/CE->getType()->isPointerType(), CE);
302+
const Type *TargetType = CE->getType().getTypePtr();
303+
if (TargetType->isPointerOrReferenceType())
304+
TargetType = TargetType->getPointeeType().getTypePtr();
305+
return this->emitGetPtrDerivedPop(DerivedOffset,
306+
/*NullOK=*/CE->getType()->isPointerType(),
307+
TargetType, CE);
305308
}
306309

307310
case CK_FloatingCast: {

clang/lib/AST/ByteCode/Interp.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1643,7 +1643,7 @@ inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
16431643
}
16441644

16451645
inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
1646-
bool NullOK) {
1646+
bool NullOK, const Type *TargetType) {
16471647
const Pointer &Ptr = S.Stk.pop<Pointer>();
16481648
if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
16491649
return false;
@@ -1661,6 +1661,20 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
16611661
if (!CheckDowncast(S, OpPC, Ptr, Off))
16621662
return false;
16631663

1664+
const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
1665+
assert(TargetRecord);
1666+
1667+
if (TargetRecord->getDecl()
1668+
->getTypeForDecl()
1669+
->getAsCXXRecordDecl()
1670+
->getCanonicalDecl() !=
1671+
TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
1672+
QualType MostDerivedType = Ptr.getDeclDesc()->getType();
1673+
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
1674+
<< MostDerivedType << QualType(TargetType, 0);
1675+
return false;
1676+
}
1677+
16641678
S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
16651679
return true;
16661680
}

clang/lib/AST/ByteCode/Opcodes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ def GetMemberPtrBasePop : Opcode {
325325
def FinishInitPop : Opcode;
326326
def FinishInit : Opcode;
327327

328-
def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool]; }
328+
def GetPtrDerivedPop : Opcode { let Args = [ArgUint32, ArgBool, ArgTypePtr]; }
329329

330330
// [Pointer] -> [Pointer]
331331
def GetPtrVirtBasePop : Opcode {

clang/test/AST/ByteCode/records.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,3 +1830,15 @@ namespace NullDtor {
18301830
static_assert(foo() == 10, ""); // both-error {{not an integral constant expression}} \
18311831
// both-note {{in call to}}
18321832
}
1833+
1834+
namespace DiamondDowncast {
1835+
struct Top {};
1836+
struct Middle1 : Top {};
1837+
struct Middle2 : Top {};
1838+
struct Bottom : Middle1, Middle2 {};
1839+
1840+
constexpr Bottom bottom;
1841+
constexpr Top &top1 = (Middle1&)bottom;
1842+
constexpr Middle2 &fail = (Middle2&)top1; // both-error {{must be initialized by a constant expression}} \
1843+
// both-note {{cannot cast object of dynamic type 'const Bottom' to type 'Middle2'}}
1844+
}

0 commit comments

Comments
 (0)