diff options
author | Timm Baeder <tbaeder@redhat.com> | 2025-05-20 11:19:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-20 11:19:24 +0200 |
commit | d01355645b1fece147163e1cfe9f71d9c704860e (patch) | |
tree | 3c05db512b3e925cf94abdb39e7090ca3b6d42ca /clang | |
parent | 2fb6ff46f62e53e821b37d3ca0a71985969eaf44 (diff) | |
download | llvm-d01355645b1fece147163e1cfe9f71d9c704860e.zip llvm-d01355645b1fece147163e1cfe9f71d9c704860e.tar.gz llvm-d01355645b1fece147163e1cfe9f71d9c704860e.tar.bz2 |
[clang][bytecode] Check downcasts for the correct type (#140689)
In multiple inheritance/diamond scenarios, we might arrive at the wrong
type.
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/AST/ByteCode/Compiler.cpp | 9 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Interp.h | 16 | ||||
-rw-r--r-- | clang/lib/AST/ByteCode/Opcodes.td | 2 | ||||
-rw-r--r-- | 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 3638054..54a4647 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 bfc6797..70bbfc5 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 9dddcce..c8db8da1 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 c2fe3d9..9361d6d 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'}} +} |