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