https://github.com/ojhunt updated 
https://github.com/llvm/llvm-project/pull/152076

>From f04f6c3e09fae50e7201a42c442e066f741f683d Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oli...@apple.com>
Date: Mon, 4 Aug 2025 20:54:46 -0700
Subject: [PATCH] [clang] Fix crash in dynamic_cast final class optimization

This corrects the codegen for the final class optimization to
correct handle the case where there is no path to perform the
cast, and also corrects the codegen to handle ptrauth protected
vtable pointers.

As part of this fix we separate out the path computation as
that makes it easier to reason about the failure code paths
and more importantly means we can know what the type of the
this object is during the cast.

The allows us to use the GetVTablePointer interface which
correctly performs the authentication operations required
when pointer authentication is enabled.

There is one place where we still lose a fully authenticated
path, and that is if there multiple paths from the source
type to the destination type. In that case we're forced to
perform a dynamic_cast to void* to find the primary base. As
we do not know the primary base at this point we do not yet
know the dynamic type of the adjusted this object and so cannot
authenticate the vtable load. The approach this PR takes to
mitigate this gap is to authenticate the vtable of the original
object, and then if the stripped vtable pointer matches the
expected type we then know the type of the object and so
perform a fully authenticated load of the vtable from the
resulting object.

Fixes #137518
---
 clang/docs/ReleaseNotes.rst                   |   3 +
 clang/lib/CodeGen/CGCXXABI.h                  |  20 ++-
 clang/lib/CodeGen/CGExprCXX.cpp               |  17 ++-
 clang/lib/CodeGen/ItaniumCXXABI.cpp           | 126 ++++++++++++-----
 clang/lib/CodeGen/MicrosoftCXXABI.cpp         |   6 +
 .../dynamic-cast-exact-disabled.cpp           |  16 +++
 clang/test/CodeGenCXX/dynamic-cast-exact.cpp  |  42 +++++-
 .../CodeGenCXX/ptrauth-dynamic-cast-exact.cpp | 128 ++++++++++++++++++
 8 files changed, 315 insertions(+), 43 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9231f2cae9bfa..d8d13edb86d7c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -160,6 +160,9 @@ Bug Fixes to C++ Support
 - Fix a crash when deleting a pointer to an incomplete array (#GH150359).
 - Fix an assertion failure when expression in assumption attribute
   (``[[assume(expr)]]``) creates temporary objects.
+- Fix the dynamic_cast to final class optimization to correctly handle
+  casts that are guaranteed to fail, and correctly handle ptrauth protected
+  vtable pointers (#GH137518).
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index 96fe04661944d..2dd320dbda976 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -294,14 +294,22 @@ class CGCXXABI {
                                              Address Value,
                                              QualType SrcRecordTy) = 0;
 
+  struct ExactDynamicCastInfo {
+    bool RequiresCastToPrimaryBase;
+    CharUnits Offset;
+  };
+
+  virtual std::optional<ExactDynamicCastInfo>
+  getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
+                          QualType DestRecordTy) = 0;
+
   /// Emit a dynamic_cast from SrcRecordTy to DestRecordTy. The cast fails if
   /// the dynamic type of Value is not exactly DestRecordTy.
-  virtual llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address 
Value,
-                                            QualType SrcRecordTy,
-                                            QualType DestTy,
-                                            QualType DestRecordTy,
-                                            llvm::BasicBlock *CastSuccess,
-                                            llvm::BasicBlock *CastFail) = 0;
+  virtual llvm::Value *emitExactDynamicCast(
+      CodeGenFunction &CGF, Address Value, QualType SrcRecordTy,
+      QualType DestTy, QualType DestRecordTy,
+      const ExactDynamicCastInfo &CastInfo, llvm::BasicBlock *CastSuccess,
+      llvm::BasicBlock *CastFail) = 0;
 
   virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
 
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index b8238a4702c4d..d392c360d5b93 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -2294,6 +2294,18 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address 
ThisAddr,
                  DestRecordTy->getAsCXXRecordDecl()->isEffectivelyFinal() &&
                  CGM.getCXXABI().shouldEmitExactDynamicCast(DestRecordTy);
 
+  std::optional<CGCXXABI::ExactDynamicCastInfo> ExactCastInfo;
+  if (IsExact) {
+    ExactCastInfo = CGM.getCXXABI().getExactDynamicCastInfo(SrcRecordTy, 
DestTy,
+                                                            DestRecordTy);
+    if (!ExactCastInfo) {
+      llvm::Value *NullValue = EmitDynamicCastToNull(*this, DestTy);
+      if (!Builder.GetInsertBlock())
+        EmitBlock(createBasicBlock("dynamic_cast.always_fails"));
+      return NullValue;
+    }
+  }
+
   // C++ [expr.dynamic.cast]p4:
   //   If the value of v is a null pointer value in the pointer case, the 
result
   //   is the null pointer value of type T.
@@ -2321,7 +2333,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address 
ThisAddr,
     // If the destination type is effectively final, this pointer points to the
     // right type if and only if its vptr has the right value.
     Value = CGM.getCXXABI().emitExactDynamicCast(
-        *this, ThisAddr, SrcRecordTy, DestTy, DestRecordTy, CastEnd, CastNull);
+        *this, ThisAddr, SrcRecordTy, DestTy, DestRecordTy, *ExactCastInfo,
+        CastEnd, CastNull);
   } else {
     assert(DestRecordTy->isRecordType() &&
            "destination type must be a record type!");
@@ -2342,12 +2355,10 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address 
ThisAddr,
   }
 
   EmitBlock(CastEnd);
-
   if (CastNull) {
     llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2);
     PHI->addIncoming(Value, CastNotNull);
     PHI->addIncoming(NullValue, CastNull);
-
     Value = PHI;
   }
 
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index f4a99467010af..9d22476506400 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -226,6 +226,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
     return hasUniqueVTablePointer(DestRecordTy);
   }
 
+  std::optional<ExactDynamicCastInfo>
+  getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
+                          QualType DestRecordTy) override;
+
   llvm::Value *emitDynamicCastCall(CodeGenFunction &CGF, Address Value,
                                    QualType SrcRecordTy, QualType DestTy,
                                    QualType DestRecordTy,
@@ -234,6 +238,7 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
   llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address ThisAddr,
                                     QualType SrcRecordTy, QualType DestTy,
                                     QualType DestRecordTy,
+                                    const ExactDynamicCastInfo &CastInfo,
                                     llvm::BasicBlock *CastSuccess,
                                     llvm::BasicBlock *CastFail) override;
 
@@ -1681,10 +1686,11 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall(
   return Value;
 }
 
-llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
-    CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
-    QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastSuccess,
-    llvm::BasicBlock *CastFail) {
+std::optional<CGCXXABI::ExactDynamicCastInfo>
+ItaniumCXXABI::getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
+                                       QualType DestRecordTy) {
+  assert(shouldEmitExactDynamicCast(DestRecordTy));
+
   ASTContext &Context = getContext();
 
   // Find all the inheritance paths.
@@ -1722,41 +1728,95 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
     if (!Offset)
       Offset = PathOffset;
     else if (Offset != PathOffset) {
-      // Base appears in at least two different places. Find the most-derived
-      // object and see if it's a DestDecl. Note that the most-derived object
-      // must be at least as aligned as this base class subobject, and must
-      // have a vptr at offset 0.
-      ThisAddr = Address(emitDynamicCastToVoid(CGF, ThisAddr, SrcRecordTy),
-                         CGF.VoidPtrTy, ThisAddr.getAlignment());
-      SrcDecl = DestDecl;
-      Offset = CharUnits::Zero();
-      break;
+      // Base appears in at least two different places.
+      return ExactDynamicCastInfo{/*RequiresCastToPrimaryBase=*/true,
+                                  CharUnits::Zero()};
     }
   }
+  if (!Offset)
+    return std::nullopt;
+  return ExactDynamicCastInfo{/*RequiresCastToPrimaryBase=*/false, *Offset};
+}
 
-  if (!Offset) {
-    // If there are no public inheritance paths, the cast always fails.
-    CGF.EmitBranch(CastFail);
-    return llvm::PoisonValue::get(CGF.VoidPtrTy);
-  }
+llvm::Value *ItaniumCXXABI::emitExactDynamicCast(
+    CodeGenFunction &CGF, Address ThisAddr, QualType SrcRecordTy,
+    QualType DestTy, QualType DestRecordTy,
+    const ExactDynamicCastInfo &ExactCastInfo, llvm::BasicBlock *CastSuccess,
+    llvm::BasicBlock *CastFail) {
+  const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+  const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
+  auto AuthenticateVTable = [&](Address ThisAddr, const CXXRecordDecl *Decl) {
+    if (!CGF.getLangOpts().PointerAuthCalls)
+      return;
+    (void)CGF.GetVTablePtr(ThisAddr, CGF.UnqualPtrTy, Decl,
+                           CodeGenFunction::VTableAuthMode::MustTrap);
+  };
+
+  bool PerformPostCastAuthentication = false;
+  llvm::Value *VTable = nullptr;
+  if (ExactCastInfo.RequiresCastToPrimaryBase) {
+    // Base appears in at least two different places. Find the most-derived
+    // object and see if it's a DestDecl. Note that the most-derived object
+    // must be at least as aligned as this base class subobject, and must
+    // have a vptr at offset 0.
+    llvm::Value *PrimaryBase =
+        emitDynamicCastToVoid(CGF, ThisAddr, SrcRecordTy);
+    ThisAddr = Address(PrimaryBase, CGF.VoidPtrTy, ThisAddr.getAlignment());
+    SrcDecl = DestDecl;
+    // This unauthenticated load is unavoidable, so we're relying on the
+    // authenticated load in the dynamic cast to void, and we'll manually
+    // authenticate the resulting v-table at the end of the cast check.
+    PerformPostCastAuthentication = CGF.getLangOpts().PointerAuthCalls;
+    CGPointerAuthInfo StrippingAuthInfo(0, PointerAuthenticationMode::Strip,
+                                        false, false, nullptr);
+    Address VTablePtrPtr = ThisAddr.withElementType(CGF.VoidPtrPtrTy);
+    VTable = CGF.Builder.CreateLoad(VTablePtrPtr, "vtable");
+    if (PerformPostCastAuthentication)
+      VTable = CGF.EmitPointerAuthAuth(StrippingAuthInfo, VTable);
+  } else
+    VTable = CGF.GetVTablePtr(ThisAddr, CGF.UnqualPtrTy, SrcDecl);
 
   // Compare the vptr against the expected vptr for the destination type at
-  // this offset. Note that we do not know what type ThisAddr points to in
-  // the case where the derived class multiply inherits from the base class
-  // so we can't use GetVTablePtr, so we load the vptr directly instead.
-  llvm::Instruction *VPtr = CGF.Builder.CreateLoad(
-      ThisAddr.withElementType(CGF.VoidPtrPtrTy), "vtable");
-  CGM.DecorateInstructionWithTBAA(
-      VPtr, CGM.getTBAAVTablePtrAccessInfo(CGF.VoidPtrPtrTy));
-  llvm::Value *Success = CGF.Builder.CreateICmpEQ(
-      VPtr, getVTableAddressPoint(BaseSubobject(SrcDecl, *Offset), DestDecl));
-  llvm::Value *Result = ThisAddr.emitRawPointer(CGF);
-  if (!Offset->isZero())
-    Result = CGF.Builder.CreateInBoundsGEP(
-        CGF.CharTy, Result,
-        {llvm::ConstantInt::get(CGF.PtrDiffTy, -Offset->getQuantity())});
+  // this offset.
+  llvm::Constant *ExpectedVTable = getVTableAddressPoint(
+      BaseSubobject(SrcDecl, ExactCastInfo.Offset), DestDecl);
+  llvm::Value *Success = CGF.Builder.CreateICmpEQ(VTable, ExpectedVTable);
+  llvm::Value *AdjustedThisPtr = ThisAddr.emitRawPointer(CGF);
+
+  if (!ExactCastInfo.Offset.isZero()) {
+    CharUnits::QuantityType Offset = ExactCastInfo.Offset.getQuantity();
+    llvm::Constant *OffsetConstant =
+        llvm::ConstantInt::get(CGF.PtrDiffTy, -Offset);
+    AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(CGF.CharTy, 
AdjustedThisPtr,
+                                                    OffsetConstant);
+    PerformPostCastAuthentication = CGF.getLangOpts().PointerAuthCalls;
+  }
+
+  if (PerformPostCastAuthentication) {
+    // If we've changed the object pointer we authenticate the vtable pointer
+    // of the resulting object.
+    llvm::BasicBlock *NonNullBlock = CGF.Builder.GetInsertBlock();
+    llvm::BasicBlock *PostCastAuthSuccess =
+        CGF.createBasicBlock("dynamic_cast.postauth.success");
+    llvm::BasicBlock *PostCastAuthComplete =
+        CGF.createBasicBlock("dynamic_cast.postauth.complete");
+    CGF.Builder.CreateCondBr(Success, PostCastAuthSuccess,
+                             PostCastAuthComplete);
+    CGF.EmitBlock(PostCastAuthSuccess);
+    Address AdjustedThisAddr =
+        Address(AdjustedThisPtr, CGF.IntPtrTy, CGF.getPointerAlign());
+    AuthenticateVTable(AdjustedThisAddr, DestDecl);
+    CGF.EmitBranch(PostCastAuthComplete);
+    CGF.EmitBlock(PostCastAuthComplete);
+    llvm::PHINode *PHI = CGF.Builder.CreatePHI(AdjustedThisPtr->getType(), 2);
+    PHI->addIncoming(AdjustedThisPtr, PostCastAuthSuccess);
+    llvm::Value *NullValue =
+        llvm::Constant::getNullValue(AdjustedThisPtr->getType());
+    PHI->addIncoming(NullValue, NonNullBlock);
+    AdjustedThisPtr = PHI;
+  }
   CGF.Builder.CreateCondBr(Success, CastSuccess, CastFail);
-  return Result;
+  return AdjustedThisPtr;
 }
 
 llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF,
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp 
b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index a181559834296..5c748615957e1 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -158,9 +158,15 @@ class MicrosoftCXXABI : public CGCXXABI {
     // TODO: Add support for exact dynamic_casts.
     return false;
   }
+  std::optional<ExactDynamicCastInfo>
+  getExactDynamicCastInfo(QualType SrcRecordTy, QualType DestTy,
+                          QualType DestRecordTy) override {
+    llvm_unreachable("unsupported");
+  }
   llvm::Value *emitExactDynamicCast(CodeGenFunction &CGF, Address Value,
                                     QualType SrcRecordTy, QualType DestTy,
                                     QualType DestRecordTy,
+                                    const ExactDynamicCastInfo &CastInfo,
                                     llvm::BasicBlock *CastSuccess,
                                     llvm::BasicBlock *CastFail) override {
     llvm_unreachable("unsupported");
diff --git a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp 
b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp
index 9a8ce1997a7f9..bf202d14c3398 100644
--- a/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp
+++ b/clang/test/CodeGenCXX/dynamic-cast-exact-disabled.cpp
@@ -13,3 +13,19 @@ B *exact(A *a) {
   // EXACT-NOT: call {{.*}} @__dynamic_cast
   return dynamic_cast<B*>(a);
 }
+
+struct C {
+  virtual ~C();
+};
+
+struct D final : private C {
+
+};
+
+// CHECK-LABEL: @_Z5exactP1C
+D *exact(C *a) {
+  // INEXACT: call {{.*}} @__dynamic_cast
+  // EXACT: entry:
+  // EXACT-NEXT: ret ptr null
+  return dynamic_cast<D*>(a);
+}
diff --git a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp 
b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
index 86e1965b4ba68..c42e8e5a2b643 100644
--- a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
+++ b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
@@ -9,6 +9,7 @@ struct E : A { int e; };
 struct F : virtual A { int f; };
 struct G : virtual A { int g; };
 struct H final : C, D, E, F, G { int h; };
+struct H1 final: C, private D { int h1; };
 
 // CHECK-LABEL: @_Z7inexactP1A
 C *inexact(A *a) {
@@ -77,10 +78,49 @@ H *exact_multi(A *a) {
   return dynamic_cast<H*>(a);
 }
 
+// CHECK-LABEL: @_Z19exact_invalid_multiP1D
+H1 *exact_invalid_multi(D* d) {
+  // CHECK:      entry:
+  // CHECK-NEXT:   %d.addr = alloca ptr
+  // CHECK-NEXT:   store ptr %d, ptr %d.addr
+  // CHECK-NEXT:   load ptr, ptr %d.addr
+  // CHECK-NEXT:   ret ptr null
+  return dynamic_cast<H1*>(d);
+}
+
+// CHECK-LABEL: @_Z19exact_invalid_multiR1D
+H1 &exact_invalid_multi(D& d) {
+  // CHECK:      entry:
+  // CHECK-NEXT:   %d.addr = alloca ptr
+  // CHECK-NEXT:   store ptr %d, ptr %d.addr
+  // CHECK-NEXT:   load ptr, ptr %d.addr
+  // CHECK-NEXT:   call void @__cxa_bad_cast()
+  // CHECK-NEXT:   unreachable
+  // CHECK:      dynamic_cast.always_fails:
+  // CHECK-NEXT:   ret ptr poison
+  return dynamic_cast<H1&>(d);
+}
+
+namespace GH137518 {
+  class base { virtual void fn() = 0; };
+  class test final : base { virtual void fn() { } };
+  test* new_test() { return new test(); }
+
+  // CHECK-LABEL: @_ZN8GH1375184castEPNS_4baseE(
+  test* cast(base* b) {
+    // CHECK:      entry:
+    // CHECK-NEXT:   %b.addr = alloca ptr
+    // CHECK-NEXT:   store ptr %b, ptr %b.addr
+    // CHECK-NEXT:   load ptr, ptr %b.addr
+    // CHECK-NEXT:   ret ptr null
+    return dynamic_cast<test*>(b);
+  }
+}
+
 namespace GH64088 {
   // Ensure we mark the B vtable as used here, because we're going to emit a
   // reference to it.
-  // CHECK: define {{.*}} @_ZN7GH640881BD0
+  // CHECK: define {{.*}} void @_ZN7GH640881BD0Ev(
   struct A { virtual ~A(); };
   struct B final : A { virtual ~B() = default; };
   B *cast(A *p) { return dynamic_cast<B*>(p); }
diff --git a/clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp 
b/clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp
new file mode 100644
index 0000000000000..1710ca5563380
--- /dev/null
+++ b/clang/test/CodeGenCXX/ptrauth-dynamic-cast-exact.cpp
@@ -0,0 +1,128 @@
+// RUN: %clang_cc1 -I%S %s -triple arm64e-apple-darwin10 -O1 -fptrauth-calls 
-fptrauth-vtable-pointer-address-discrimination  
-fptrauth-vtable-pointer-type-discrimination -emit-llvm -std=c++11 -o - | 
FileCheck %s --check-prefixes=CHECK
+
+struct A {
+  virtual ~A();
+};
+struct B {
+  int foo;
+  virtual ~B();
+};
+struct C final : A, B {
+  virtual void f(){};
+};
+struct D final : B, A {
+  virtual void f(){};
+};
+
+struct Offset {
+  virtual ~Offset();
+};
+struct E {
+  virtual ~E();
+};
+struct F final : Offset, E {
+};
+struct G {
+  virtual ~G();
+  int g;
+};
+struct H : E {
+  int h;
+};
+struct I : E {
+  int i;
+};
+struct J : virtual E {
+  int j;
+};
+struct K : virtual E {
+  int k;
+};
+struct L final : G, H, I, J, K {
+  int l;
+};
+struct M final: G, private H { int m; };
+
+// CHECK-LABEL: @_Z10exact_to_CP1A
+C *exact_to_C(A *a) {
+  // CHECK: [[UNAUTHED_VPTR:%.*]] = load ptr, ptr %a, align 8
+  // CHECK: [[VPTR_ADDRI:%.*]] = ptrtoint ptr %a to i64
+  // CHECK: [[VPTR_ADDR_DISC:%.*]] = tail call i64 @llvm.ptrauth.blend(i64 
[[VPTR_ADDRI]], i64 62866)
+  // CHECK: [[UNAUTHED_VPTRI:%.*]] = ptrtoint ptr [[UNAUTHED_VPTR]] to i64
+  // CHECK: [[AUTHED_VPTRI:%.*]] = tail call i64 @llvm.ptrauth.auth(i64 
[[UNAUTHED_VPTRI]], i32 2, i64 [[VPTR_ADDR_DISC]])
+  // CHECK: [[IS_EXPECTED:%.*]] = icmp eq i64 [[AUTHED_VPTRI]], ptrtoint (ptr 
getelementptr inbounds nuw inrange(-16, 24) (i8, ptr @_ZTV1C, i64 16) to i64)
+  // CHECK: br i1 [[IS_EXPECTED]], label %dynamic_cast.end, label 
%dynamic_cast.null
+  // CHECK: [[NULL_CHECKED_RESULT:%.*]] = phi ptr [ %a, %dynamic_cast.notnull 
], [ null, %dynamic_cast.null ]
+  // CHECK: ret ptr [[NULL_CHECKED_RESULT]]
+  return dynamic_cast<C*>(a);
+}
+
+// CHECK-LABEL: @_Z9exact_t_DP1A
+D *exact_t_D(A *a) {
+  // CHECK: dynamic_cast.notnull:
+  // CHECK:   [[SRC_UNAUTHED_VPTR:%.*]] = load ptr, ptr %a
+  // CHECK:   [[SRC_VPTR_ADDRI:%.*]] = ptrtoint ptr %a to i64
+  // CHECK:   [[SRC_VPTR_DISC:%.*]] = tail call i64 @llvm.ptrauth.blend(i64 
[[SRC_VPTR_ADDRI]], i64 62866)
+  // CHECK:   [[SRC_UNAUTHED_VPTRI:%.*]] = ptrtoint ptr [[SRC_UNAUTHED_VPTR]] 
to i64
+  // CHECK:   [[SRC_AUTHED_VPTRI:%.*]] = tail call i64 @llvm.ptrauth.auth(i64 
[[SRC_UNAUTHED_VPTRI]], i32 2, i64 [[SRC_VPTR_DISC]])
+  // CHECK:   [[SUCCESS:%.*]] = icmp eq i64 [[SRC_AUTHED_VPTRI]], ptrtoint 
(ptr getelementptr inbounds nuw inrange(-16, 16) (i8, ptr @_ZTV1D, i64 56) to 
i64)
+  // CHECK:   br i1 [[SUCCESS]], label %dynamic_cast.postauth.success, label 
%dynamic_cast.postauth.complete
+  // CHECK: dynamic_cast.postauth.success:
+  // CHECK:   [[ADJUSTED_THIS:%.*]] = getelementptr inbounds i8, ptr %a, i64 
-16
+  // CHECK:   [[ADJUSTED_UNAUTHED_VPTR:%.*]] = load ptr, ptr [[ADJUSTED_THIS]]
+  // CHECK:   [[ADJUSTED_VPTR_ADDRI:%.*]] = ptrtoint ptr [[ADJUSTED_THIS]] to 
i64
+  // CHECK:   [[ADJUSTED_VPTR_DISC:%.*]] = tail call i64 
@llvm.ptrauth.blend(i64 [[ADJUSTED_VPTR_ADDRI]], i64 28965)
+  // CHECK:   [[ADJUSTED_UNAUTHED_VPTRI:%.*]] = ptrtoint ptr 
[[ADJUSTED_UNAUTHED_VPTR]] to i64
+  // CHECK:   [[ADJUSTED_AUTHED_VPTRI:%.*]] = tail call i64 
@llvm.ptrauth.auth(i64 [[ADJUSTED_UNAUTHED_VPTRI]], i32 2, i64 
[[ADJUSTED_VPTR_DISC]])
+  // CHECK:   [[ADJUSTED_AUTHED_VPTR:%.*]] = inttoptr i64 
[[ADJUSTED_AUTHED_VPTRI]] to ptr
+  // CHECK:   br label %dynamic_cast.postauth.complete
+  // CHECK: dynamic_cast.postauth.complete:
+  // CHECK:   [[AUTHED_ADJUSTED_THIS:%.*]] = phi ptr [ [[ADJUSTED_THIS]], 
%dynamic_cast.postauth.success ], [ null, %dynamic_cast.notnull ]
+  // CHECK:   br i1 [[SUCCESS]], label %dynamic_cast.end, label 
%dynamic_cast.null
+  // CHECK: dynamic_cast.null:
+  // CHECK:   br label %dynamic_cast.end
+  // CHECK: dynamic_cast.end:
+  // CHECK:   [[RESULT:%.*]] = phi ptr [ [[AUTHED_ADJUSTED_THIS]], 
%dynamic_cast.postauth.complete ], [ null, %dynamic_cast.null ]
+  // CHECK:   ret ptr [[RESULT]]
+  return dynamic_cast<D*>(a);
+}
+
+// CHECK-LABEL: @_Z11exact_multiP1E
+L *exact_multi(E *e) {
+  // CHECK: dynamic_cast.notnull:
+  // CHECK:   [[VTABLE_ADDR:%.*]] = load ptr, ptr %e, align 8
+  // CHECK:   [[THIS_ADDRI:%.*]] = ptrtoint ptr %e to i64
+  // CHECK:   [[VTABLE_DISC:%.*]] = tail call i64 @llvm.ptrauth.blend(i64 
[[THIS_ADDRI]], i64 12810)
+  // CHECK:   [[VTABLE_ADDRI:%.*]] = ptrtoint ptr [[VTABLE_ADDR]] to i64
+  // CHECK:   [[AUTHED_VTABLEI:%.*]] = tail call i64 @llvm.ptrauth.auth(i64 
[[VTABLE_ADDRI]], i32 2, i64 [[VTABLE_DISC]])
+  // CHECK:   [[AUTHED_VTABLE:%.*]] = inttoptr i64 [[AUTHED_VTABLEI]] to ptr
+  // CHECK:   [[PRIMARY_BASE_OFFSET:%.*]] = getelementptr inbounds i8, ptr 
[[AUTHED_VTABLE]], i64 -16
+  // CHECK:   %offset.to.top = load i64, ptr [[PRIMARY_BASE_OFFSET]]
+  // CHECK:   [[ADJUSTED_THIS:%.*]] = getelementptr inbounds i8, ptr %e, i64 
%offset.to.top
+  // CHECK:   [[ADJUSTED_THIS_VTABLE:%.*]] = load ptr, ptr [[ADJUSTED_THIS]]
+  // CHECK:   [[ADJUSTED_THIS_VTABLEI:%.*]] = ptrtoint ptr 
[[ADJUSTED_THIS_VTABLE]] to i64
+  // CHECK:   [[ADJUSTED_THIS_STRIPPED_VTABLEI:%.*]] = tail call i64 
@llvm.ptrauth.strip(i64 [[ADJUSTED_THIS_VTABLEI]], i32 0)
+  // CHECK:   [[SUCCESS:%.*]] = icmp eq i64 
[[ADJUSTED_THIS_STRIPPED_VTABLEI]], ptrtoint (ptr getelementptr inbounds nuw 
inrange(-24, 16) (i8, ptr @_ZTV1L, i64 24) to i64)
+  // CHECK:   br i1 [[SUCCESS]], label %dynamic_cast.postauth.success, label 
%dynamic_cast.postauth.complete
+  // CHECK: dynamic_cast.postauth.success:
+  // CHECK:   [[ADJUSTED_THISI:%.*]] = ptrtoint ptr [[ADJUSTED_THIS]] to i64
+  // CHECK:   [[DEST_DISC:%.*]] = tail call i64 @llvm.ptrauth.blend(i64 
[[ADJUSTED_THISI]], i64 41434)
+  // CHECK:   tail call i64 @llvm.ptrauth.auth(i64 [[ADJUSTED_THIS_VTABLEI]], 
i32 2, i64 [[DEST_DISC]])
+  // CHECK:   br label %dynamic_cast.postauth.complete
+  // CHECK: dynamic_cast.postauth.complete:
+  // CHECK:   [[AUTHED_ADJUSTED_THIS:%.*]] = phi ptr [ [[ADJUSTED_THIS]], 
%dynamic_cast.postauth.success ], [ null, %dynamic_cast.notnull ]
+  // CHECK:   br i1 [[SUCCESS]], label %dynamic_cast.end, label 
%dynamic_cast.null
+  // CHECK: dynamic_cast.null:
+  // CHECK:   br label %dynamic_cast.end
+  // CHECK: dynamic_cast.end:
+  // CHECK:   [[RESULT:%.*]] = phi ptr [ [[AUTHED_ADJUSTED_THIS]], 
%dynamic_cast.postauth.complete ], [ null, %dynamic_cast.null ]
+  // CHECK:   ret ptr [[RESULT]]
+  return dynamic_cast<L*>(e);
+}
+
+// CHECK-LABEL: @_Z19exact_invalid_multiP1H
+M *exact_invalid_multi(H* d) {
+  // CHECK: entry:
+  // CHECK-NEXT:   ret ptr null
+  return dynamic_cast<M*>(d);
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to