[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