@@ -226,6 +226,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
226
226
return hasUniqueVTablePointer (DestRecordTy);
227
227
}
228
228
229
+ std::optional<ExactDynamicCastInfo>
230
+ getExactDynamicCastInfo (QualType SrcRecordTy, QualType DestTy,
231
+ QualType DestRecordTy) override ;
232
+
229
233
llvm::Value *emitDynamicCastCall (CodeGenFunction &CGF, Address Value,
230
234
QualType SrcRecordTy, QualType DestTy,
231
235
QualType DestRecordTy,
@@ -234,6 +238,7 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
234
238
llvm::Value *emitExactDynamicCast (CodeGenFunction &CGF, Address ThisAddr,
235
239
QualType SrcRecordTy, QualType DestTy,
236
240
QualType DestRecordTy,
241
+ const ExactDynamicCastInfo &CastInfo,
237
242
llvm::BasicBlock *CastSuccess,
238
243
llvm::BasicBlock *CastFail) override ;
239
244
@@ -1681,10 +1686,11 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
1681
1686
return Value;
1682
1687
}
1683
1688
1684
- llvm::Value *ItaniumCXXABI::emitExactDynamicCast (
1685
- CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
1686
- QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastSuccess,
1687
- llvm::BasicBlock *CastFail) {
1689
+ std::optional<CGCXXABI::ExactDynamicCastInfo>
1690
+ ItaniumCXXABI::getExactDynamicCastInfo (QualType SrcRecordTy, QualType DestTy,
1691
+ QualType DestRecordTy) {
1692
+ assert (shouldEmitExactDynamicCast (DestRecordTy));
1693
+
1688
1694
ASTContext &Context = getContext ();
1689
1695
1690
1696
// Find all the inheritance paths.
@@ -1722,41 +1728,95 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
1722
1728
if (!Offset)
1723
1729
Offset = PathOffset;
1724
1730
else if (Offset != PathOffset) {
1725
- // Base appears in at least two different places. Find the most-derived
1726
- // object and see if it's a DestDecl. Note that the most-derived object
1727
- // must be at least as aligned as this base class subobject, and must
1728
- // have a vptr at offset 0.
1729
- ThisAddr = Address (emitDynamicCastToVoid (CGF, ThisAddr, SrcRecordTy),
1730
- CGF.VoidPtrTy , ThisAddr.getAlignment ());
1731
- SrcDecl = DestDecl;
1732
- Offset = CharUnits::Zero ();
1733
- break ;
1731
+ // Base appears in at least two different places.
1732
+ return ExactDynamicCastInfo{/* RequiresCastToPrimaryBase=*/ true ,
1733
+ CharUnits::Zero ()};
1734
1734
}
1735
1735
}
1736
+ if (!Offset)
1737
+ return std::nullopt;
1738
+ return ExactDynamicCastInfo{/* RequiresCastToPrimaryBase=*/ false , *Offset};
1739
+ }
1736
1740
1737
- if (!Offset) {
1738
- // If there are no public inheritance paths, the cast always fails.
1739
- CGF.EmitBranch (CastFail);
1740
- return llvm::PoisonValue::get (CGF.VoidPtrTy );
1741
- }
1741
+ llvm::Value *ItaniumCXXABI::emitExactDynamicCast (
1742
+ CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
1743
+ QualType DestTy, QualType DestRecordTy,
1744
+ const ExactDynamicCastInfo &ExactCastInfo, llvm::BasicBlock *CastSuccess,
1745
+ llvm::BasicBlock *CastFail) {
1746
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl ();
1747
+ const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl ();
1748
+ auto AuthenticateVTable = [&](Address ThisAddr, const CXXRecordDecl *Decl) {
1749
+ if (!CGF.getLangOpts ().PointerAuthCalls )
1750
+ return ;
1751
+ (void )CGF.GetVTablePtr (ThisAddr, CGF.UnqualPtrTy , Decl,
1752
+ CodeGenFunction::VTableAuthMode::MustTrap);
1753
+ };
1754
+
1755
+ bool PerformPostCastAuthentication = false ;
1756
+ llvm::Value *VTable = nullptr ;
1757
+ if (ExactCastInfo.RequiresCastToPrimaryBase ) {
1758
+ // Base appears in at least two different places. Find the most-derived
1759
+ // object and see if it's a DestDecl. Note that the most-derived object
1760
+ // must be at least as aligned as this base class subobject, and must
1761
+ // have a vptr at offset 0.
1762
+ llvm::Value *PrimaryBase =
1763
+ emitDynamicCastToVoid (CGF, ThisAddr, SrcRecordTy);
1764
+ ThisAddr = Address (PrimaryBase, CGF.VoidPtrTy , ThisAddr.getAlignment ());
1765
+ SrcDecl = DestDecl;
1766
+ // This unauthenticated load is unavoidable, so we're relying on the
1767
+ // authenticated load in the dynamic cast to void, and we'll manually
1768
+ // authenticate the resulting v-table at the end of the cast check.
1769
+ PerformPostCastAuthentication = CGF.getLangOpts ().PointerAuthCalls ;
1770
+ CGPointerAuthInfo StrippingAuthInfo (0 , PointerAuthenticationMode::Strip,
1771
+ false , false , nullptr );
1772
+ Address VTablePtrPtr = ThisAddr.withElementType (CGF.VoidPtrPtrTy );
1773
+ VTable = CGF.Builder .CreateLoad (VTablePtrPtr, " vtable" );
1774
+ if (PerformPostCastAuthentication)
1775
+ VTable = CGF.EmitPointerAuthAuth (StrippingAuthInfo, VTable);
1776
+ } else
1777
+ VTable = CGF.GetVTablePtr (ThisAddr, CGF.UnqualPtrTy , SrcDecl);
1742
1778
1743
1779
// Compare the vptr against the expected vptr for the destination type at
1744
- // this offset. Note that we do not know what type ThisAddr points to in
1745
- // the case where the derived class multiply inherits from the base class
1746
- // so we can't use GetVTablePtr, so we load the vptr directly instead.
1747
- llvm::Instruction *VPtr = CGF.Builder .CreateLoad (
1748
- ThisAddr.withElementType (CGF.VoidPtrPtrTy ), " vtable" );
1749
- CGM.DecorateInstructionWithTBAA (
1750
- VPtr, CGM.getTBAAVTablePtrAccessInfo (CGF.VoidPtrPtrTy ));
1751
- llvm::Value *Success = CGF.Builder .CreateICmpEQ (
1752
- VPtr, getVTableAddressPoint (BaseSubobject (SrcDecl, *Offset), DestDecl));
1753
- llvm::Value *Result = ThisAddr.emitRawPointer (CGF);
1754
- if (!Offset->isZero ())
1755
- Result = CGF.Builder .CreateInBoundsGEP (
1756
- CGF.CharTy , Result,
1757
- {llvm::ConstantInt::get (CGF.PtrDiffTy , -Offset->getQuantity ())});
1780
+ // this offset.
1781
+ llvm::Constant *ExpectedVTable = getVTableAddressPoint (
1782
+ BaseSubobject (SrcDecl, ExactCastInfo.Offset ), DestDecl);
1783
+ llvm::Value *Success = CGF.Builder .CreateICmpEQ (VTable, ExpectedVTable);
1784
+ llvm::Value *AdjustedThisPtr = ThisAddr.emitRawPointer (CGF);
1785
+
1786
+ if (!ExactCastInfo.Offset .isZero ()) {
1787
+ CharUnits::QuantityType Offset = ExactCastInfo.Offset .getQuantity ();
1788
+ llvm::Constant *OffsetConstant =
1789
+ llvm::ConstantInt::get (CGF.PtrDiffTy , -Offset);
1790
+ AdjustedThisPtr = CGF.Builder .CreateInBoundsGEP (CGF.CharTy , AdjustedThisPtr,
1791
+ OffsetConstant);
1792
+ PerformPostCastAuthentication = CGF.getLangOpts ().PointerAuthCalls ;
1793
+ }
1794
+
1795
+ if (PerformPostCastAuthentication) {
1796
+ // If we've changed the object pointer we authenticate the vtable pointer
1797
+ // of the resulting object.
1798
+ llvm::BasicBlock *NonNullBlock = CGF.Builder .GetInsertBlock ();
1799
+ llvm::BasicBlock *PostCastAuthSuccess =
1800
+ CGF.createBasicBlock (" dynamic_cast.postauth.success" );
1801
+ llvm::BasicBlock *PostCastAuthComplete =
1802
+ CGF.createBasicBlock (" dynamic_cast.postauth.complete" );
1803
+ CGF.Builder .CreateCondBr (Success, PostCastAuthSuccess,
1804
+ PostCastAuthComplete);
1805
+ CGF.EmitBlock (PostCastAuthSuccess);
1806
+ Address AdjustedThisAddr =
1807
+ Address (AdjustedThisPtr, CGF.IntPtrTy , CGF.getPointerAlign ());
1808
+ AuthenticateVTable (AdjustedThisAddr, DestDecl);
1809
+ CGF.EmitBranch (PostCastAuthComplete);
1810
+ CGF.EmitBlock (PostCastAuthComplete);
1811
+ llvm::PHINode *PHI = CGF.Builder .CreatePHI (AdjustedThisPtr->getType (), 2 );
1812
+ PHI->addIncoming (AdjustedThisPtr, PostCastAuthSuccess);
1813
+ llvm::Value *NullValue =
1814
+ llvm::Constant::getNullValue (AdjustedThisPtr->getType ());
1815
+ PHI->addIncoming (NullValue, NonNullBlock);
1816
+ AdjustedThisPtr = PHI;
1817
+ }
1758
1818
CGF.Builder .CreateCondBr (Success, CastSuccess, CastFail);
1759
- return Result ;
1819
+ return AdjustedThisPtr ;
1760
1820
}
1761
1821
1762
1822
llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid (CodeGenFunction &CGF,
0 commit comments