[clang] f6b06b4 - [PAC] Implement function pointer re-signing (#98847)

via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 18 07:51:21 PDT 2024


Author: Akira Hatanaka
Date: 2024-07-18T07:51:17-07:00
New Revision: f6b06b42a3f4f59ff33da20d42358f2768eaf726

URL: https://github.com/llvm/llvm-project/commit/f6b06b42a3f4f59ff33da20d42358f2768eaf726
DIFF: https://github.com/llvm/llvm-project/commit/f6b06b42a3f4f59ff33da20d42358f2768eaf726.diff

LOG: [PAC] Implement function pointer re-signing (#98847)

Re-signing occurs when function type discrimination is enabled and a
function pointer is converted to another function pointer type that
requires signing using a different discriminator. A function pointer is
re-signed using discriminator zero when it's converted to a pointer to a
non-function type such as `void*`.

---------

Co-authored-by: Ahmed Bougacha <ahmed at bougacha.org>
Co-authored-by: John McCall <rjmccall at apple.com>

Added: 
    clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c
    clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c

Modified: 
    clang/lib/CodeGen/Address.h
    clang/lib/CodeGen/CGBuilder.h
    clang/lib/CodeGen/CGExpr.cpp
    clang/lib/CodeGen/CGExprScalar.cpp
    clang/lib/CodeGen/CGPointerAuth.cpp
    clang/lib/CodeGen/CGValue.h
    clang/lib/CodeGen/CodeGenFunction.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/lib/Headers/ptrauth.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/Address.h b/clang/lib/CodeGen/Address.h
index 35ec370a139c9..1c4d2e103b5e7 100644
--- a/clang/lib/CodeGen/Address.h
+++ b/clang/lib/CodeGen/Address.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H
 #define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H
 
+#include "CGPointerAuthInfo.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/PointerIntPair.h"
@@ -108,6 +109,22 @@ class RawAddress {
 
 /// Like RawAddress, an abstract representation of an aligned address, but the
 /// pointer contained in this class is possibly signed.
+///
+/// This is designed to be an IR-level abstraction, carrying just the
+/// information necessary to perform IR operations on an address like loads and
+/// stores.  In particular, it doesn't carry C type information or allow the
+/// representation of things like bit-fields; clients working at that level
+/// should generally be using `LValue`.
+///
+/// An address may be either *raw*, meaning that it's an ordinary machine
+/// pointer, or *signed*, meaning that the pointer carries an embedded
+/// pointer-authentication signature. Representing signed pointers directly in
+/// this abstraction allows the authentication to be delayed as long as possible
+/// without forcing IRGen to use totally 
diff erent code paths for signed and
+/// unsigned values or to separately propagate signature information through
+/// every API that manipulates addresses. Pointer arithmetic on signed addresses
+/// (e.g. drilling down to a struct field) is accumulated into a separate offset
+/// which is applied when the address is finally accessed.
 class Address {
   friend class CGBuilderTy;
 
@@ -121,7 +138,11 @@ class Address {
 
   CharUnits Alignment;
 
-  /// Offset from the base pointer.
+  /// The ptrauth information needed to authenticate the base pointer.
+  CGPointerAuthInfo PtrAuthInfo;
+
+  /// Offset from the base pointer. This is non-null only when the base
+  /// pointer is signed.
   llvm::Value *Offset = nullptr;
 
   llvm::Value *emitRawPointerSlow(CodeGenFunction &CGF) const;
@@ -140,12 +161,14 @@ class Address {
   }
 
   Address(llvm::Value *BasePtr, llvm::Type *ElementType, CharUnits Alignment,
-          llvm::Value *Offset, KnownNonNull_t IsKnownNonNull = NotKnownNonNull)
+          CGPointerAuthInfo PtrAuthInfo, llvm::Value *Offset,
+          KnownNonNull_t IsKnownNonNull = NotKnownNonNull)
       : Pointer(BasePtr, IsKnownNonNull), ElementType(ElementType),
-        Alignment(Alignment), Offset(Offset) {}
+        Alignment(Alignment), PtrAuthInfo(PtrAuthInfo), Offset(Offset) {}
 
   Address(RawAddress RawAddr)
-      : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr),
+      : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr,
+                RawAddr.isValid() ? RawAddr.isKnownNonNull() : NotKnownNonNull),
         ElementType(RawAddr.isValid() ? RawAddr.getElementType() : nullptr),
         Alignment(RawAddr.isValid() ? RawAddr.getAlignment()
                                     : CharUnits::Zero()) {}
@@ -192,6 +215,9 @@ class Address {
   /// Return the IR name of the pointer value.
   llvm::StringRef getName() const { return Pointer.getPointer()->getName(); }
 
+  const CGPointerAuthInfo &getPointerAuthInfo() const { return PtrAuthInfo; }
+  void setPointerAuthInfo(const CGPointerAuthInfo &Info) { PtrAuthInfo = Info; }
+
   // This function is called only in CGBuilderBaseTy::CreateElementBitCast.
   void setElementType(llvm::Type *Ty) {
     assert(hasOffset() &&
@@ -199,6 +225,8 @@ class Address {
     ElementType = Ty;
   }
 
+  bool isSigned() const { return PtrAuthInfo.isSigned(); }
+
   /// Whether the pointer is known not to be null.
   KnownNonNull_t isKnownNonNull() const {
     assert(isValid());
@@ -215,6 +243,9 @@ class Address {
 
   llvm::Value *getOffset() const { return Offset; }
 
+  Address getResignedAddress(const CGPointerAuthInfo &NewInfo,
+                             CodeGenFunction &CGF) const;
+
   /// Return the pointer contained in this class after authenticating it and
   /// adding offset to it if necessary.
   llvm::Value *emitRawPointer(CodeGenFunction &CGF) const {
@@ -240,7 +271,8 @@ class Address {
   /// alignment.
   Address withElementType(llvm::Type *ElemTy) const {
     if (!hasOffset())
-      return Address(getBasePointer(), ElemTy, getAlignment(), nullptr,
+      return Address(getBasePointer(), ElemTy, getAlignment(),
+                     getPointerAuthInfo(), /*Offset=*/nullptr,
                      isKnownNonNull());
     Address A(*this);
     A.ElementType = ElemTy;

diff  --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h
index 0bc4fda62979c..5d59d5a4ae2c1 100644
--- a/clang/lib/CodeGen/CGBuilder.h
+++ b/clang/lib/CodeGen/CGBuilder.h
@@ -190,8 +190,8 @@ class CGBuilderTy : public CGBuilderBaseTy {
                               const llvm::Twine &Name = "") {
     if (!Addr.hasOffset())
       return Address(CreateAddrSpaceCast(Addr.getBasePointer(), Ty, Name),
-                     ElementTy, Addr.getAlignment(), nullptr,
-                     Addr.isKnownNonNull());
+                     ElementTy, Addr.getAlignment(), Addr.getPointerAuthInfo(),
+                     /*Offset=*/nullptr, Addr.isKnownNonNull());
     // Eagerly force a raw address if these is an offset.
     return RawAddress(
         CreateAddrSpaceCast(Addr.emitRawPointer(*getCGF()), Ty, Name),

diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 5fdd3cc490e59..6a0af00b9e186 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1312,7 +1312,8 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
         if (CE->getCastKind() == CK_AddressSpaceConversion)
           Addr = CGF.Builder.CreateAddrSpaceCast(
               Addr, CGF.ConvertType(E->getType()), ElemTy);
-        return Addr;
+        return CGF.authPointerToPointerCast(Addr, CE->getSubExpr()->getType(),
+                                            CE->getType());
       }
       break;
 

diff  --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 084dc54537eb7..a17d68424bbce 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2374,7 +2374,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
       DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo());
       return EmitLoadOfLValue(DestLV, CE->getExprLoc());
     }
-    return Builder.CreateBitCast(Src, DstTy);
+
+    llvm::Value *Result = Builder.CreateBitCast(Src, DstTy);
+    return CGF.authPointerToPointerCast(Result, E->getType(), DestTy);
   }
   case CK_AddressSpaceConversion: {
     Expr::EvalResult Result;
@@ -2524,6 +2526,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
       if (DestTy.mayBeDynamicClass())
         IntToPtr = Builder.CreateLaunderInvariantGroup(IntToPtr);
     }
+
+    IntToPtr = CGF.authPointerToPointerCast(IntToPtr, E->getType(), DestTy);
     return IntToPtr;
   }
   case CK_PointerToIntegral: {
@@ -2539,6 +2543,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
         PtrExpr = Builder.CreateStripInvariantGroup(PtrExpr);
     }
 
+    PtrExpr = CGF.authPointerToPointerCast(PtrExpr, E->getType(), DestTy);
     return Builder.CreatePtrToInt(PtrExpr, ConvertType(DestTy));
   }
   case CK_ToVoid: {

diff  --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index 621d567dde721..7fe62c0788742 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -15,6 +15,7 @@
 #include "CodeGenModule.h"
 #include "clang/CodeGen/CodeGenABITypes.h"
 #include "clang/CodeGen/ConstantInitBuilder.h"
+#include "llvm/Analysis/ValueTracking.h"
 #include "llvm/Support/SipHash.h"
 
 using namespace clang;
@@ -165,6 +166,128 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {
   return ::getPointerAuthInfoForType(*this, T);
 }
 
+static bool isZeroConstant(const llvm::Value *Value) {
+  if (const auto *CI = dyn_cast<llvm::ConstantInt>(Value))
+    return CI->isZero();
+  return false;
+}
+
+static bool equalAuthPolicies(const CGPointerAuthInfo &Left,
+                              const CGPointerAuthInfo &Right) {
+  assert((Left.isSigned() || Right.isSigned()) &&
+         "shouldn't be called if neither is signed");
+  if (Left.isSigned() != Right.isSigned())
+    return false;
+  return Left.getKey() == Right.getKey() &&
+         Left.getAuthenticationMode() == Right.getAuthenticationMode();
+}
+
+// Return the discriminator or return zero if the discriminator is null.
+static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info,
+                                           CGBuilderTy &Builder) {
+  llvm::Value *Discriminator = Info.getDiscriminator();
+  return Discriminator ? Discriminator : Builder.getSize(0);
+}
+
+llvm::Value *
+CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value,
+                                           const CGPointerAuthInfo &CurAuth,
+                                           const CGPointerAuthInfo &NewAuth) {
+  assert(CurAuth && NewAuth);
+
+  if (CurAuth.getAuthenticationMode() !=
+          PointerAuthenticationMode::SignAndAuth ||
+      NewAuth.getAuthenticationMode() !=
+          PointerAuthenticationMode::SignAndAuth) {
+    llvm::Value *AuthedValue = EmitPointerAuthAuth(CurAuth, Value);
+    return EmitPointerAuthSign(NewAuth, AuthedValue);
+  }
+  // Convert the pointer to intptr_t before signing it.
+  auto *OrigType = Value->getType();
+  Value = Builder.CreatePtrToInt(Value, IntPtrTy);
+
+  auto *CurKey = Builder.getInt32(CurAuth.getKey());
+  auto *NewKey = Builder.getInt32(NewAuth.getKey());
+
+  llvm::Value *CurDiscriminator = getDiscriminatorOrZero(CurAuth, Builder);
+  llvm::Value *NewDiscriminator = getDiscriminatorOrZero(NewAuth, Builder);
+
+  // call i64 @llvm.ptrauth.resign(i64 %pointer,
+  //                               i32 %curKey, i64 %curDiscriminator,
+  //                               i32 %newKey, i64 %newDiscriminator)
+  auto *Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_resign);
+  Value = EmitRuntimeCall(
+      Intrinsic, {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator});
+
+  // Convert back to the original type.
+  Value = Builder.CreateIntToPtr(Value, OrigType);
+  return Value;
+}
+
+llvm::Value *CodeGenFunction::emitPointerAuthResign(
+    llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo,
+    const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) {
+  // Fast path: if neither schema wants a signature, we're done.
+  if (!CurAuthInfo && !NewAuthInfo)
+    return Value;
+
+  llvm::Value *Null = nullptr;
+  // If the value is obviously null, we're done.
+  if (auto *PointerValue = dyn_cast<llvm::PointerType>(Value->getType())) {
+    Null = CGM.getNullPointer(PointerValue, Type);
+  } else {
+    assert(Value->getType()->isIntegerTy());
+    Null = llvm::ConstantInt::get(IntPtrTy, 0);
+  }
+  if (Value == Null)
+    return Value;
+
+  // If both schemas sign the same way, we're done.
+  if (equalAuthPolicies(CurAuthInfo, NewAuthInfo)) {
+    const llvm::Value *CurD = CurAuthInfo.getDiscriminator();
+    const llvm::Value *NewD = NewAuthInfo.getDiscriminator();
+    if (CurD == NewD)
+      return Value;
+
+    if ((CurD == nullptr && isZeroConstant(NewD)) ||
+        (NewD == nullptr && isZeroConstant(CurD)))
+      return Value;
+  }
+
+  llvm::BasicBlock *InitBB = Builder.GetInsertBlock();
+  llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr;
+
+  // Null pointers have to be mapped to null, and the ptrauth_resign
+  // intrinsic doesn't do that.
+  if (!IsKnownNonNull && !llvm::isKnownNonZero(Value, CGM.getDataLayout())) {
+    ContBB = createBasicBlock("resign.cont");
+    ResignBB = createBasicBlock("resign.nonnull");
+
+    auto *IsNonNull = Builder.CreateICmpNE(Value, Null);
+    Builder.CreateCondBr(IsNonNull, ResignBB, ContBB);
+    EmitBlock(ResignBB);
+  }
+
+  // Perform the auth/sign/resign operation.
+  if (!NewAuthInfo)
+    Value = EmitPointerAuthAuth(CurAuthInfo, Value);
+  else if (!CurAuthInfo)
+    Value = EmitPointerAuthSign(NewAuthInfo, Value);
+  else
+    Value = emitPointerAuthResignCall(Value, CurAuthInfo, NewAuthInfo);
+
+  // Clean up with a phi if we branched before.
+  if (ContBB) {
+    EmitBlock(ContBB);
+    auto *Phi = Builder.CreatePHI(Value->getType(), 2);
+    Phi->addIncoming(Null, InitBB);
+    Phi->addIncoming(Value, ResignBB);
+    Value = Phi;
+  }
+
+  return Value;
+}
+
 llvm::Constant *
 CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
                                         llvm::Constant *StorageAddress,
@@ -351,3 +474,110 @@ CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,
                            /* IsIsaPointer */ false,
                            /* AuthenticatesNullValues */ false, Discriminator);
 }
+
+llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,
+                                                       QualType SourceType,
+                                                       QualType DestType) {
+  CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
+  if (SourceType->isSignableType())
+    CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
+
+  if (DestType->isSignableType())
+    NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
+
+  if (!CurAuthInfo && !NewAuthInfo)
+    return ResultPtr;
+
+  // If only one side of the cast is a function pointer, then we still need to
+  // resign to handle casts to/from opaque pointers.
+  if (!CurAuthInfo && DestType->isFunctionPointerType())
+    CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType);
+
+  if (!NewAuthInfo && SourceType->isFunctionPointerType())
+    NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
+
+  return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo,
+                               /*IsKnownNonNull=*/false);
+}
+
+Address CodeGenFunction::authPointerToPointerCast(Address Ptr,
+                                                  QualType SourceType,
+                                                  QualType DestType) {
+  CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
+  if (SourceType->isSignableType())
+    CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
+
+  if (DestType->isSignableType())
+    NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
+
+  if (!CurAuthInfo && !NewAuthInfo)
+    return Ptr;
+
+  if (!CurAuthInfo && DestType->isFunctionPointerType()) {
+    // When casting a non-signed pointer to a function pointer, just set the
+    // auth info on Ptr to the assumed schema. The pointer will be resigned to
+    // the effective type when used.
+    Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType));
+    return Ptr;
+  }
+
+  if (!NewAuthInfo && SourceType->isFunctionPointerType()) {
+    NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
+    Ptr = Ptr.getResignedAddress(NewAuthInfo, *this);
+    Ptr.setPointerAuthInfo(CGPointerAuthInfo());
+    return Ptr;
+  }
+
+  return Ptr;
+}
+
+Address CodeGenFunction::getAsNaturalAddressOf(Address Addr,
+                                               QualType PointeeTy) {
+  CGPointerAuthInfo Info =
+      PointeeTy.isNull() ? CGPointerAuthInfo()
+                         : CGM.getPointerAuthInfoForPointeeType(PointeeTy);
+  return Addr.getResignedAddress(Info, *this);
+}
+
+Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo,
+                                    CodeGenFunction &CGF) const {
+  assert(isValid() && "pointer isn't valid");
+  CGPointerAuthInfo CurInfo = getPointerAuthInfo();
+  llvm::Value *Val;
+
+  // Nothing to do if neither the current or the new ptrauth info needs signing.
+  if (!CurInfo.isSigned() && !NewInfo.isSigned())
+    return Address(getBasePointer(), getElementType(), getAlignment(),
+                   isKnownNonNull());
+
+  assert(ElementType && "Effective type has to be set");
+  assert(!Offset && "unexpected non-null offset");
+
+  // If the current and the new ptrauth infos are the same and the offset is
+  // null, just cast the base pointer to the effective type.
+  if (CurInfo == NewInfo && !hasOffset())
+    Val = getBasePointer();
+  else
+    Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo,
+                                    NewInfo, isKnownNonNull());
+
+  Val = CGF.Builder.CreateBitCast(Val, getType());
+  return Address(Val, getElementType(), getAlignment(), NewInfo,
+                 /*Offset=*/nullptr, isKnownNonNull());
+}
+
+llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {
+  assert(isSimple());
+  return emitResignedPointer(getType(), CGF);
+}
+
+llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,
+                                         CodeGenFunction &CGF) const {
+  assert(isSimple());
+  return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer();
+}
+
+llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {
+  assert(isSimple());
+  return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;
+}

diff  --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h
index f1ba3cf95ae59..c4ec8d207d2e3 100644
--- a/clang/lib/CodeGen/CGValue.h
+++ b/clang/lib/CodeGen/CGValue.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_LIB_CODEGEN_CGVALUE_H
 
 #include "Address.h"
+#include "CGPointerAuthInfo.h"
 #include "CodeGenTBAA.h"
 #include "EHScopeStack.h"
 #include "clang/AST/ASTContext.h"
@@ -233,9 +234,6 @@ class LValue {
   // this lvalue.
   bool Nontemporal : 1;
 
-  // The pointer is known not to be null.
-  bool IsKnownNonNull : 1;
-
   LValueBaseInfo BaseInfo;
   TBAAAccessInfo TBAAInfo;
 
@@ -263,7 +261,6 @@ class LValue {
     this->ImpreciseLifetime = false;
     this->Nontemporal = false;
     this->ThreadLocalRef = false;
-    this->IsKnownNonNull = false;
     this->BaseIvarExp = nullptr;
   }
 
@@ -349,28 +346,26 @@ class LValue {
   LValueBaseInfo getBaseInfo() const { return BaseInfo; }
   void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; }
 
-  KnownNonNull_t isKnownNonNull() const {
-    return (KnownNonNull_t)IsKnownNonNull;
-  }
+  KnownNonNull_t isKnownNonNull() const { return Addr.isKnownNonNull(); }
   LValue setKnownNonNull() {
-    IsKnownNonNull = true;
+    Addr.setKnownNonNull();
     return *this;
   }
 
   // simple lvalue
-  llvm::Value *getPointer(CodeGenFunction &CGF) const {
-    assert(isSimple());
-    return Addr.getBasePointer();
-  }
-  llvm::Value *emitRawPointer(CodeGenFunction &CGF) const {
-    assert(isSimple());
-    return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;
-  }
+  llvm::Value *getPointer(CodeGenFunction &CGF) const;
+  llvm::Value *emitResignedPointer(QualType PointeeTy,
+                                   CodeGenFunction &CGF) const;
+  llvm::Value *emitRawPointer(CodeGenFunction &CGF) const;
 
   Address getAddress() const { return Addr; }
 
   void setAddress(Address address) { Addr = address; }
 
+  CGPointerAuthInfo getPointerAuthInfo() const {
+    return Addr.getPointerAuthInfo();
+  }
+
   // vector elt lvalue
   Address getVectorAddress() const {
     assert(isVectorElt());

diff  --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index ea4635c039cb2..551db09165dbe 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -195,34 +195,46 @@ CodeGenFunction::CGFPOptionsRAII::~CGFPOptionsRAII() {
   CGF.Builder.setDefaultConstrainedRounding(OldRounding);
 }
 
-static LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T,
-                                         bool ForPointeeType,
-                                         CodeGenFunction &CGF) {
+static LValue
+makeNaturalAlignAddrLValue(llvm::Value *V, QualType T, bool ForPointeeType,
+                           bool MightBeSigned, CodeGenFunction &CGF,
+                           KnownNonNull_t IsKnownNonNull = NotKnownNonNull) {
   LValueBaseInfo BaseInfo;
   TBAAAccessInfo TBAAInfo;
   CharUnits Alignment =
       CGF.CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo, ForPointeeType);
-  Address Addr = Address(V, CGF.ConvertTypeForMem(T), Alignment);
+  Address Addr =
+      MightBeSigned
+          ? CGF.makeNaturalAddressForPointer(V, T, Alignment, false, nullptr,
+                                             nullptr, IsKnownNonNull)
+          : Address(V, CGF.ConvertTypeForMem(T), Alignment, IsKnownNonNull);
   return CGF.MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo);
 }
 
-LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
-  return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this);
+LValue
+CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T,
+                                            KnownNonNull_t IsKnownNonNull) {
+  return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false,
+                                      /*MightBeSigned*/ true, *this,
+                                      IsKnownNonNull);
 }
 
 LValue
 CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) {
-  return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this);
+  return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true,
+                                      /*MightBeSigned*/ true, *this);
 }
 
 LValue CodeGenFunction::MakeNaturalAlignRawAddrLValue(llvm::Value *V,
                                                       QualType T) {
-  return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this);
+  return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false,
+                                      /*MightBeSigned*/ false, *this);
 }
 
 LValue CodeGenFunction::MakeNaturalAlignPointeeRawAddrLValue(llvm::Value *V,
                                                              QualType T) {
-  return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this);
+  return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true,
+                                      /*MightBeSigned*/ false, *this);
 }
 
 llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 9fe4391237819..d83e38cab8e2d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -202,7 +202,7 @@ template <> struct DominatingValue<Address> {
   }
   static type restore(CodeGenFunction &CGF, saved_type value) {
     return Address(DominatingLLVMValue::restore(CGF, value.BasePtr),
-                   value.ElementType, value.Alignment,
+                   value.ElementType, value.Alignment, CGPointerAuthInfo(),
                    DominatingLLVMValue::restore(CGF, value.Offset));
   }
 };
@@ -2689,7 +2689,8 @@ class CodeGenFunction : public CodeGenTypeCache {
     if (Alignment.isZero())
       Alignment =
           CGM.getNaturalTypeAlignment(T, BaseInfo, TBAAInfo, ForPointeeType);
-    return Address(Ptr, ConvertTypeForMem(T), Alignment, nullptr,
+    return Address(Ptr, ConvertTypeForMem(T), Alignment,
+                   CGM.getPointerAuthInfoForPointeeType(T), /*Offset=*/nullptr,
                    IsKnownNonNull);
   }
 
@@ -2730,7 +2731,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// an l-value with the natural pointee alignment of T.
   LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T);
 
-  LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T);
+  LValue
+  MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T,
+                             KnownNonNull_t IsKnownNonNull = NotKnownNonNull);
 
   /// Same as MakeNaturalAlignPointeeAddrLValue except that the pointer is known
   /// to be unsigned.
@@ -4424,10 +4427,6 @@ class CodeGenFunction : public CodeGenTypeCache {
                                                CXXDtorType Type,
                                                const CXXRecordDecl *RD);
 
-  llvm::Value *getAsNaturalPointerTo(Address Addr, QualType PointeeType) {
-    return Addr.getBasePointer();
-  }
-
   bool isPointerKnownNonNull(const Expr *E);
 
   /// Create the discriminator from the storage address and the entity hash.
@@ -4437,16 +4436,36 @@ class CodeGenFunction : public CodeGenTypeCache {
                                         llvm::Value *StorageAddress,
                                         GlobalDecl SchemaDecl,
                                         QualType SchemaType);
-  llvm::Value *EmitPointerAuthSign(QualType PointeeType, llvm::Value *Pointer);
+
   llvm::Value *EmitPointerAuthSign(const CGPointerAuthInfo &Info,
                                    llvm::Value *Pointer);
+
   llvm::Value *EmitPointerAuthAuth(const CGPointerAuthInfo &Info,
                                    llvm::Value *Pointer);
 
+  llvm::Value *emitPointerAuthResign(llvm::Value *Pointer, QualType PointerType,
+                                     const CGPointerAuthInfo &CurAuthInfo,
+                                     const CGPointerAuthInfo &NewAuthInfo,
+                                     bool IsKnownNonNull);
+  llvm::Value *emitPointerAuthResignCall(llvm::Value *Pointer,
+                                         const CGPointerAuthInfo &CurInfo,
+                                         const CGPointerAuthInfo &NewInfo);
+
   void EmitPointerAuthOperandBundle(
       const CGPointerAuthInfo &Info,
       SmallVectorImpl<llvm::OperandBundleDef> &Bundles);
 
+  llvm::Value *authPointerToPointerCast(llvm::Value *ResultPtr,
+                                        QualType SourceType, QualType DestType);
+  Address authPointerToPointerCast(Address Ptr, QualType SourceType,
+                                   QualType DestType);
+
+  Address getAsNaturalAddressOf(Address Addr, QualType PointeeTy);
+
+  llvm::Value *getAsNaturalPointerTo(Address Addr, QualType PointeeType) {
+    return getAsNaturalAddressOf(Addr, PointeeType).getBasePointer();
+  }
+
   // Return the copy constructor name with the prefix "__copy_constructor_"
   // removed.
   static std::string getNonTrivialCopyConstructorStr(QualType QT,

diff  --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 40ac6dcac2ab8..e0bc8c4f9acf7 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -58,6 +58,21 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
 /* Authenticating a pointer that was not signed with the given key
    and extra-data value will (likely) fail by trapping. */
 
+/* The null function pointer is always the all-zero bit pattern.
+   Signing an all-zero bit pattern will embed a (likely) non-zero
+   signature in the result, and so the result will not seem to be
+   a null function pointer.  Authenticating this value will yield
+   a null function pointer back.  However, authenticating an
+   all-zero bit pattern will probably fail, because the
+   authentication will expect a (likely) non-zero signature to
+   embedded in the value.
+
+   Because of this, if a pointer may validly be null, you should
+   check for null before attempting to authenticate it with one
+   of these intrinsics.  This is not necessary when using the
+   __ptrauth qualifier; the compiler will perform this check
+   automatically. */
+
 #if __has_feature(ptrauth_intrinsics)
 
 /* Strip the signature from a value without authenticating it.

diff  --git a/clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c b/clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c
new file mode 100644
index 0000000000000..7d76649e2e49c
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- -fptrauth-function-pointer-type-discrimination | FileCheck -check-prefixes CHECK,TYPE %s
+// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck -check-prefixes CHECK,ZERO %s
+
+typedef void (*fptr_t)(void);
+
+char *cptr;
+void (*fptr)(void);
+
+// CHECK-LABEL: define void @test1
+void test1() {
+  // TYPE: [[LOAD:%.*]] = load ptr, ptr @cptr
+  // TYPE: [[TOINT:%.*]] = ptrtoint ptr [[LOAD]] to i64
+  // TYPE: call i64 @llvm.ptrauth.resign(i64 [[TOINT]], i32 0, i64 0, i32 0, i64 18983)
+  // TYPE: call void {{.*}}() [ "ptrauth"(i32 0, i64 18983) ]
+  // ZERO-NOT: @llvm.ptrauth.resign
+
+  (*(fptr_t)cptr)();
+}
+
+// CHECK-LABEL: define i8 @test2
+char test2() {
+  return *(char *)fptr;
+
+  // TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr
+  // TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+  // TYPE-NEXT: br i1 [[CMP]], label %[[NONNULL:.*]], label %[[CONT:.*]]
+
+  // TYPE: [[NONNULL]]:
+  // TYPE: [[TOINT:%.*]] = ptrtoint ptr [[LOAD]] to i64
+  // TYPE: [[CALL:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[TOINT]], i32 0, i64 18983, i32 0, i64 0)
+  // TYPE: [[TOPTR:%.*]] = inttoptr i64 [[CALL]] to ptr
+
+  // TYPE: [[CONT]]:
+  // TYPE: phi ptr [ null, {{.*}} ], [ [[TOPTR]], %[[NONNULL]] ]
+  // ZERO-NOT: @llvm.ptrauth.resign
+}
+
+// CHECK-LABEL: define void @test4
+void test4() {
+  (*((fptr_t)(&*((char *)(&*(fptr_t)cptr)))))();
+
+  // CHECK: [[LOAD:%.*]] = load ptr, ptr @cptr
+  // TYPE-NEXT: [[CAST4:%.*]] = ptrtoint ptr [[LOAD]] to i64
+  // TYPE-NEXT: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST4]], i32 0, i64 0, i32 0, i64 18983)
+  // TYPE-NEXT: [[CAST5:%.*]] = inttoptr i64 [[RESIGN]] to ptr
+  // TYPE-NEXT: call void [[CAST5]]() [ "ptrauth"(i32 0, i64 18983) ]
+  // ZERO-NOT: @llvm.ptrauth.resign
+  // ZERO: call void [[LOAD]]() [ "ptrauth"(i32 0, i64 0) ]
+}
+
+void *vptr;
+// CHECK-LABEL: define void @test5
+void test5() {
+  vptr = &*(char *)fptr;
+
+  // TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr
+  // TYPE-NEXT: [[CMP]] = icmp ne ptr [[LOAD]], null
+  // TYPE-NEXT: br i1 [[CMP]], label %[[NONNULL:.*]], label %[[CONT:.*]]
+
+  // TYPE: [[NONNULL]]:
+  // TYPE: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 18983, i32 0, i64 0)
+  // TYPE: [[CAST:%.*]] = inttoptr i64 [[RESIGN]] to ptr
+
+  // TYPE: [[CONT]]:
+  // TYPE: [[PHI:%.*]] = phi ptr [ null, {{.*}} ], [ [[CAST]], %[[NONNULL]] ]
+  // TYPE: store ptr [[PHI]], ptr @vptr
+  // ZERO-NOT: @llvm.ptrauth.resign
+}

diff  --git a/clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c b/clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c
new file mode 100644
index 0000000000000..cdf9ee4907525
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,TYPE
+// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,ZERO
+// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CHECKCXX,TYPE,TYPECXX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void f(void);
+void f2(int);
+void (*fptr)(void);
+void *opaque;
+unsigned long uintptr;
+
+#ifdef __cplusplus
+struct ptr_member {
+  void (*fptr_)(int) = 0;
+};
+ptr_member pm;
+void (*test_member)() = (void (*)())pm.fptr_;
+
+// CHECKCXX-LABEL: define internal void @__cxx_global_var_init
+// TYPECXX: call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 2712, i32 0, i64 18983)
+#endif
+
+
+// CHECK-LABEL: define void @test_cast_to_opaque
+void test_cast_to_opaque() {
+  opaque = (void *)f;
+
+  // TYPE: [[RESIGN_VAL:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @f, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 0, i64 0)
+  // TYPE: [[RESIGN_PTR:%.*]] = inttoptr i64 [[RESIGN_VAL]] to ptr
+  // ZERO-NOT: @llvm.ptrauth.resign
+}
+
+// CHECK-LABEL: define void @test_cast_from_opaque
+void test_cast_from_opaque() {
+  fptr = (void (*)(void))opaque;
+
+  // TYPE: [[LOAD:%.*]] = load ptr, ptr @opaque
+  // TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+  // TYPE: br i1 [[CMP]], label %[[RESIGN_LAB:.*]], label
+
+  // TYPE: [[RESIGN_LAB]]:
+  // TYPE: [[INT:%.*]] = ptrtoint ptr [[LOAD]] to i64
+  // TYPE: [[RESIGN_INT:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[INT]], i32 0, i64 0, i32 0, i64 18983)
+
+  // ZERO-NOT: @llvm.ptrauth.resign
+}
+
+// CHECK-LABEL: define void @test_cast_to_intptr
+void test_cast_to_intptr() {
+  uintptr = (unsigned long)fptr;
+
+  // TYPE: [[ENTRY:.*]]:
+  // TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr
+  // TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
+  // TYPE: br i1 [[CMP]], label %[[RESIGN_LAB:.*]], label %[[RESIGN_CONT:.*]]
+
+  // TYPE: [[RESIGN_LAB]]:
+  // TYPE: [[INT:%.*]] = ptrtoint ptr [[LOAD]] to i64
+  // TYPE: [[RESIGN_INT:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[INT]], i32 0, i64 18983, i32 0, i64 0)
+  // TYPE: [[RESIGN:%.*]] = inttoptr i64 [[RESIGN_INT]] to ptr
+  // TYPE: br label %[[RESIGN_CONT]]
+
+  // TYPE: [[RESIGN_CONT]]:
+  // TYPE: phi ptr [ null, %[[ENTRY]] ], [ [[RESIGN]], %[[RESIGN_LAB]] ]
+
+  // ZERO-NOT: @llvm.ptrauth.resign
+}
+
+// CHECK-LABEL: define void @test_function_to_function_cast
+void test_function_to_function_cast() {
+  void (*fptr2)(int) = (void (*)(int))fptr;
+  // TYPE: call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 18983, i32 0, i64 2712)
+  // ZERO-NOT: @llvm.ptrauth.resign
+}
+
+// CHECK-LABEL: define void @test_call_lvalue_cast
+void test_call_lvalue_cast() {
+  (*(void (*)(int))f)(42);
+
+  // TYPE: entry:
+  // TYPE-NEXT: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @f, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 0, i64 2712)
+  // TYPE-NEXT: [[RESIGN_INT:%.*]] = inttoptr i64 [[RESIGN]] to ptr
+  // TYPE-NEXT: call void [[RESIGN_INT]](i32 noundef 42) [ "ptrauth"(i32 0, i64 2712) ]
+  // ZERO-NOT: @llvm.ptrauth.resign
+  // ZERO: call void ptrauth (ptr @f, i32 0)(i32 noundef 42) [ "ptrauth"(i32 0, i64 0) ]
+}
+
+
+#ifdef __cplusplus
+}
+#endif


        


More information about the cfe-commits mailing list