[clang] [lldb] [clang] Add `__ptrauth_restricted_intptr` qualifier (PR #137580)
Oliver Hunt via cfe-commits
cfe-commits at lists.llvm.org
Fri May 2 22:01:02 PDT 2025
https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/137580
>From 9c29520abea852086f8f4c555e2ad1ea7c711800 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sun, 27 Apr 2025 22:33:44 -0700
Subject: [PATCH] [clang] Add `__ptrauth_restricted_intptr` qualifier
__ptrauth_restricted_intptr provides a mechanism to apply pointer
authentication to pointer sized integer types.
---
clang/docs/PointerAuthentication.rst | 14 ++
clang/docs/ReleaseNotes.rst | 2 +-
clang/include/clang/AST/Type.h | 52 +++--
clang/include/clang/Basic/Attr.td | 3 +-
.../clang/Basic/DiagnosticSemaKinds.td | 31 ++-
clang/include/clang/Basic/Features.def | 1 +
clang/include/clang/Basic/TokenKinds.def | 1 +
clang/include/clang/Sema/Sema.h | 3 +-
clang/lib/AST/ASTContext.cpp | 3 +
clang/lib/AST/Type.cpp | 6 +
clang/lib/AST/TypePrinter.cpp | 5 +-
clang/lib/CodeGen/CGExprConstant.cpp | 4 +
clang/lib/CodeGen/CGExprScalar.cpp | 2 +-
clang/lib/CodeGen/CGPointerAuth.cpp | 22 +-
clang/lib/Parse/ParseDecl.cpp | 9 +-
clang/lib/Sema/SemaCast.cpp | 2 +-
clang/lib/Sema/SemaChecking.cpp | 10 +-
clang/lib/Sema/SemaDecl.cpp | 3 +-
clang/lib/Sema/SemaDeclCXX.cpp | 2 +-
clang/lib/Sema/SemaObjCProperty.cpp | 6 +-
clang/lib/Sema/SemaType.cpp | 49 ++--
clang/lib/Sema/TreeTransform.h | 21 +-
.../ptrauth-restricted-intptr-qualifier.c | 220 ++++++++++++++++++
.../ptrauth-restricted-intptr-qualifier.c | 45 ++++
clang/test/SemaCXX/ptrauth-triviality.cpp | 44 ++++
.../SymbolFile/DWARF/DWARFASTParserClang.cpp | 7 +-
26 files changed, 491 insertions(+), 76 deletions(-)
create mode 100644 clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c
create mode 100644 clang/test/Sema/ptrauth-restricted-intptr-qualifier.c
diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst
index 41818d43ac687..2278971d757c9 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -326,6 +326,20 @@ a discriminator determined as follows:
is ``ptrauth_blend_discriminator(&x, discriminator)``; see
`ptrauth_blend_discriminator`_.
+__ptrauth_restricted_intptr qualifier
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This is a variant of the ``__ptrauth`` qualifier, that applies to pointer sized
+integers. See the documentation for ``__ptrauth qualifier``.
+
+This feature exists to support older APIs that use [u]intptrs to hold opaque
+pointer types.
+
+Care must be taken to avoid using the signature bit components of the signed
+integers or subsequent authentication of the signed value may fail.
+
+Note: When applied to a global initialiser a signed uintptr can only be
+initialised with the value 0 or a global address.
+
``<ptrauth.h>``
~~~~~~~~~~~~~~~
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4bd9d904e1ea9..da901e93b4498 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -698,7 +698,7 @@ Arm and AArch64 Support
- When a feature that depends on NEON (``simd``) is used, NEON is now automatically enabled.
- When NEON is disabled (``+nosimd``), all features that depend on NEON will now be disabled.
-- Support for __ptrauth type qualifier has been added.
+- Support for __ptrauth and __ptrauth_restricted_intptr type qualifiers has been added.
- For AArch64, added support for generating executable-only code sections by using the
``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688)
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 3e1fb05ad537c..246b4aeba7876 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -168,8 +168,13 @@ class PointerAuthQualifier {
AuthenticatesNullValuesBits = 1,
AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1)
<< AuthenticatesNullValuesShift,
- KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
- KeyBits = 10,
+ RestrictedIntegralShift =
+ AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
+ RestrictedIntegralBits = 1,
+ RestrictedIntegralMask = ((1 << RestrictedIntegralBits) - 1)
+ << RestrictedIntegralShift,
+ KeyShift = RestrictedIntegralShift + RestrictedIntegralBits,
+ KeyBits = 9,
KeyMask = ((1 << KeyBits) - 1) << KeyShift,
DiscriminatorShift = KeyShift + KeyBits,
DiscriminatorBits = 16,
@@ -178,32 +183,33 @@ class PointerAuthQualifier {
// bits: |0 |1 |2..3 |4 |
// |Enabled|Address|AuthenticationMode|ISA pointer|
- // bits: |5 |6..15| 16...31 |
- // |AuthenticatesNull|Key |Discriminator|
+ // bits: |5 |6 |7..15| 16...31 |
+ // |AuthenticatesNull|RestrictedIntegral|Key |Discriminator|
uint32_t Data = 0;
// The following static assertions check that each of the 32 bits is present
// exactly in one of the constants.
static_assert((EnabledBits + AddressDiscriminatedBits +
AuthenticationModeBits + IsaPointerBits +
- AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) ==
- 32,
+ AuthenticatesNullValuesBits + RestrictedIntegralBits +
+ KeyBits + DiscriminatorBits) == 32,
"PointerAuthQualifier should be exactly 32 bits");
static_assert((EnabledMask + AddressDiscriminatedMask +
AuthenticationModeMask + IsaPointerMask +
- AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) ==
- 0xFFFFFFFF,
+ AuthenticatesNullValuesMask + RestrictedIntegralMask +
+ KeyMask + DiscriminatorMask) == 0xFFFFFFFF,
"All masks should cover the entire bits");
static_assert((EnabledMask ^ AddressDiscriminatedMask ^
AuthenticationModeMask ^ IsaPointerMask ^
- AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) ==
- 0xFFFFFFFF,
+ AuthenticatesNullValuesMask ^ RestrictedIntegralMask ^
+ KeyMask ^ DiscriminatorMask) == 0xFFFFFFFF,
"All masks should cover the entire bits");
PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated,
unsigned ExtraDiscriminator,
PointerAuthenticationMode AuthenticationMode,
- bool IsIsaPointer, bool AuthenticatesNullValues)
+ bool IsIsaPointer, bool AuthenticatesNullValues,
+ bool IsRestrictedIntegral)
: Data(EnabledMask |
(IsAddressDiscriminated
? llvm::to_underlying(AddressDiscriminatedMask)
@@ -212,8 +218,8 @@ class PointerAuthQualifier {
(llvm::to_underlying(AuthenticationMode)
<< AuthenticationModeShift) |
(ExtraDiscriminator << DiscriminatorShift) |
- (IsIsaPointer << IsaPointerShift) |
- (AuthenticatesNullValues << AuthenticatesNullValuesShift)) {
+ (AuthenticatesNullValues << AuthenticatesNullValuesShift) |
+ (IsRestrictedIntegral << RestrictedIntegralShift)) {
assert(Key <= KeyNoneInternal);
assert(ExtraDiscriminator <= MaxDiscriminator);
assert((Data == 0) ==
@@ -237,13 +243,13 @@ class PointerAuthQualifier {
static PointerAuthQualifier
Create(unsigned Key, bool IsAddressDiscriminated, unsigned ExtraDiscriminator,
PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer,
- bool AuthenticatesNullValues) {
+ bool AuthenticatesNullValues, bool IsRestrictedIntegral) {
if (Key == PointerAuthKeyNone)
Key = KeyNoneInternal;
assert(Key <= KeyNoneInternal && "out-of-range key value");
return PointerAuthQualifier(Key, IsAddressDiscriminated, ExtraDiscriminator,
AuthenticationMode, IsIsaPointer,
- AuthenticatesNullValues);
+ AuthenticatesNullValues, IsRestrictedIntegral);
}
bool isPresent() const {
@@ -290,6 +296,10 @@ class PointerAuthQualifier {
return hasKeyNone() ? PointerAuthQualifier() : *this;
}
+ bool isRestrictedIntegral() const {
+ return (Data & RestrictedIntegralMask) >> RestrictedIntegralShift;
+ }
+
friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
return Lhs.Data == Rhs.Data;
}
@@ -2563,7 +2573,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
bool isPointerType() const;
bool isPointerOrReferenceType() const;
- bool isSignableType() const;
+ bool isSignableType(const ASTContext &Ctx) const;
+ bool isSignablePointerType() const;
+ bool isSignableIntegerType(const ASTContext &Ctx) const;
bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
bool isCountAttributedType() const;
bool isBlockPointerType() const;
@@ -8216,7 +8228,13 @@ inline bool Type::isAnyPointerType() const {
return isPointerType() || isObjCObjectPointerType();
}
-inline bool Type::isSignableType() const { return isPointerType(); }
+inline bool Type::isSignableType(const ASTContext &Ctx) const {
+ return isSignablePointerType() || isSignableIntegerType(Ctx);
+}
+
+inline bool Type::isSignablePointerType() const {
+ return isPointerType() || isObjCClassType() || isObjCQualifiedClassType();
+}
inline bool Type::isBlockPointerType() const {
return isa<BlockPointerType>(CanonicalType);
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index a734eb6658c3d..487f0776991f0 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3578,7 +3578,8 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
}
def PointerAuth : TypeAttr {
- let Spellings = [CustomKeyword<"__ptrauth">];
+ let Spellings = [CustomKeyword<"__ptrauth">,
+ CustomKeyword<"__ptrauth_restricted_intptr">];
let Args = [IntArgument<"Key">,
BoolArgument<"AddressDiscriminated", 1>,
IntArgument<"ExtraDiscriminator", 1>];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e5a7cdc14a737..f3e0fcedd7a8e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1025,20 +1025,27 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error<
"supported with ptrauth indirect gotos">;
// __ptrauth qualifier
-def err_ptrauth_qualifier_invalid : Error<
- "%select{return type|parameter type|property}1 may not be qualified with '__ptrauth'; type is %0">;
-def err_ptrauth_qualifier_cast : Error<
- "cannot cast to '__ptrauth'-qualified type %0">;
-def err_ptrauth_qualifier_nonpointer : Error<
- "'__ptrauth' qualifier only applies to pointer types; %0 is invalid">;
+def err_ptrauth_qualifier_invalid
+ : Error<
+ "%select{return type|parameter type|property}0 may not be qualified "
+ "with '%select{__ptrauth_restricted_intptr|__ptrauth}1'; type is %2">;
+def err_ptrauth_qualifier_cast : Error<"cannot cast to "
+ "'%select{__ptrauth_restricted_intptr|__"
+ "ptrauth}0'-qualified type %1">;
+def err_ptrauth_qualifier_invalid_target
+ : Error<"'%select{__ptrauth_restricted_intptr|__ptrauth}0' qualifier only "
+ "applies to %select{pointer sized integer|pointer}0 types; %1 is "
+ "invalid">;
def err_ptrauth_qualifier_redundant : Error<
"type %0 is already %1-qualified">;
-def err_ptrauth_arg_not_ice : Error<
- "argument to '__ptrauth' must be an integer constant expression">;
-def err_ptrauth_address_discrimination_invalid : Error<
- "invalid address discrimination flag '%0'; '__ptrauth' requires '0' or '1'">;
-def err_ptrauth_extra_discriminator_invalid : Error<
- "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between '0' and '%1'">;
+def err_ptrauth_arg_not_ice
+ : Error<"argument to '%0' must be an integer constant expression">;
+def err_ptrauth_address_discrimination_invalid
+ : Error<
+ "invalid address discrimination flag '%0'; '%1' requires '0' or '1'">;
+def err_ptrauth_extra_discriminator_invalid
+ : Error<"invalid extra discriminator flag '%0'; '%1' requires a value "
+ "between '0' and '%2'">;
/// main()
// static main() is not an error in C, just in C++.
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 14bff8a68846d..c859167e47e57 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -108,6 +108,7 @@ FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics)
+EXTENSION(ptrauth_restricted_intptr_qualifier, LangOpts.PointerAuthIntrinsics)
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index fb53d88deea4a..01a5d85b7f287 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -349,6 +349,7 @@ KEYWORD(__func__ , KEYALL)
KEYWORD(__objc_yes , KEYALL)
KEYWORD(__objc_no , KEYALL)
KEYWORD(__ptrauth , KEYALL)
+KEYWORD(__ptrauth_restricted_intptr , KEYALL)
// C2y
UNARY_EXPR_OR_TYPE_TRAIT(_Countof, CountOf, KEYNOCXX)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 19343eb0af092..55ecca309500f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3850,7 +3850,8 @@ class Sema final : public SemaBase {
bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key);
- bool checkPointerAuthDiscriminatorArg(Expr *Arg, PointerAuthDiscArgKind Kind,
+ bool checkPointerAuthDiscriminatorArg(const AttributeCommonInfo &AttrInfo,
+ Expr *Arg, PointerAuthDiscArgKind Kind,
unsigned &IntVal);
/// Diagnose function specifiers on a declaration of an identifier that
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index ae136ae271882..42888579b1a6c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2925,6 +2925,9 @@ bool ASTContext::hasUniqueObjectRepresentations(
// All integrals and enums are unique.
if (Ty->isIntegralOrEnumerationType()) {
+ // Address discriminated __ptrauth_restricted_intptr types are not unique
+ if (Ty.hasAddressDiscriminatedPointerAuth())
+ return false;
// Except _BitInt types that have padding bits.
if (const auto *BIT = Ty->getAs<BitIntType>())
return getTypeSize(BIT) == BIT->getNumBits();
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 59369fba2e772..a61dc2ad6d787 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5087,6 +5087,12 @@ AttributedType::stripOuterNullability(QualType &T) {
return std::nullopt;
}
+bool Type::isSignableIntegerType(const ASTContext &Ctx) const {
+ if (!isIntegralType(Ctx) || isEnumeralType())
+ return false;
+ return Ctx.getTypeSize(this) == Ctx.getTypeSize(Ctx.VoidPtrTy);
+}
+
bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const {
const auto *objcPtr = getAs<ObjCObjectPointerType>();
if (!objcPtr)
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index cba1a2d98d660..fe4283abc7017 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2534,7 +2534,10 @@ void PointerAuthQualifier::print(raw_ostream &OS,
if (!isPresent())
return;
- OS << "__ptrauth(";
+ if (isRestrictedIntegral())
+ OS << "__ptrauth_restricted_intptr(";
+ else
+ OS << "__ptrauth(";
OS << getKey();
OS << "," << unsigned(isAddressDiscriminated()) << ","
<< getExtraDiscriminator() << ")";
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index b21ebeee4bed1..ebe6bb80504b5 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2444,6 +2444,10 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, QualType DestType,
EnablePtrAuthFunctionTypeDiscrimination)
.tryEmit();
case APValue::Int:
+ if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth();
+ PointerAuth &&
+ (PointerAuth.authenticatesNullValues() || Value.getInt() != 0))
+ return nullptr;
return llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getInt());
case APValue::FixedPoint:
return llvm::ConstantInt::get(CGM.getLLVMContext(),
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 15a6177746403..968f9e214c6ce 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2287,7 +2287,7 @@ static bool isLValueKnownNonNull(CodeGenFunction &CGF, const Expr *E) {
}
bool CodeGenFunction::isPointerKnownNonNull(const Expr *E) {
- assert(E->getType()->isSignableType());
+ assert(E->getType()->isSignableType(getContext()));
E = E->IgnoreParens();
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index 0a183a8524c17..01f43630edce3 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -175,7 +175,7 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {
/// pointer type.
static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,
QualType PointerType) {
- assert(PointerType->isSignableType());
+ assert(PointerType->isSignableType(CGM.getContext()));
// Block pointers are currently not signed.
if (PointerType->isBlockPointerType())
@@ -209,7 +209,7 @@ emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV,
/// needlessly resigning the pointer.
std::pair<llvm::Value *, CGPointerAuthInfo>
CodeGenFunction::EmitOrigPointerRValue(const Expr *E) {
- assert(E->getType()->isSignableType());
+ assert(E->getType()->isSignableType(getContext()));
E = E->IgnoreParens();
if (const auto *Load = dyn_cast<ImplicitCastExpr>(E)) {
@@ -291,7 +291,10 @@ static bool equalAuthPolicies(const CGPointerAuthInfo &Left,
if (Left.isSigned() != Right.isSigned())
return false;
return Left.getKey() == Right.getKey() &&
- Left.getAuthenticationMode() == Right.getAuthenticationMode();
+ Left.getAuthenticationMode() == Right.getAuthenticationMode() &&
+ Left.isIsaPointer() == Right.isIsaPointer() &&
+ Left.authenticatesNullValues() == Right.authenticatesNullValues() &&
+ Left.getDiscriminator() == Right.getDiscriminator();
}
// Return the discriminator or return zero if the discriminator is null.
@@ -590,8 +593,9 @@ CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
}
return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator,
PointerAuthenticationMode::SignAndAuth,
- /* IsIsaPointer */ false,
- /* AuthenticatesNullValues */ false);
+ /*IsIsaPointer=*/false,
+ /*AuthenticatesNullValues=*/false,
+ /*IsRestrictedIntegral=*/false);
}
std::optional<PointerAuthQualifier>
@@ -642,10 +646,10 @@ llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,
QualType SourceType,
QualType DestType) {
CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
- if (SourceType->isSignableType())
+ if (SourceType->isSignableType(getContext()))
CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
- if (DestType->isSignableType())
+ if (DestType->isSignableType(getContext()))
NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
if (!CurAuthInfo && !NewAuthInfo)
@@ -667,10 +671,10 @@ Address CodeGenFunction::authPointerToPointerCast(Address Ptr,
QualType SourceType,
QualType DestType) {
CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
- if (SourceType->isSignableType())
+ if (SourceType->isSignableType(getContext()))
CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
- if (DestType->isSignableType())
+ if (DestType->isSignableType(getContext()))
NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
if (!CurAuthInfo && !NewAuthInfo)
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 4cfb8de615f05..297d508d52b93 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3402,11 +3402,12 @@ void Parser::DistributeCLateParsedAttrs(Decl *Dcl,
}
/// type-qualifier:
-/// ('__ptrauth') '(' constant-expression
+/// ('__ptrauth' | '__ptrauth_restricted_intptr') '(' constant-expression
/// (',' constant-expression)[opt]
/// (',' constant-expression)[opt] ')'
void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) {
- assert(Tok.is(tok::kw___ptrauth));
+ assert(Tok.is(tok::kw___ptrauth) ||
+ Tok.is(tok::kw___ptrauth_restricted_intptr));
IdentifierInfo *KwName = Tok.getIdentifierInfo();
SourceLocation KwLoc = ConsumeToken();
@@ -4309,6 +4310,7 @@ void Parser::ParseDeclarationSpecifiers(
// __ptrauth qualifier.
case tok::kw___ptrauth:
+ case tok::kw___ptrauth_restricted_intptr:
ParsePtrauthQualifier(DS.getAttributes());
continue;
@@ -6027,6 +6029,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___pascal:
case tok::kw___unaligned:
case tok::kw___ptrauth:
+ case tok::kw___ptrauth_restricted_intptr:
case tok::kw__Nonnull:
case tok::kw__Nullable:
@@ -6317,6 +6320,7 @@ bool Parser::isDeclarationSpecifier(
case tok::kw___pascal:
case tok::kw___unaligned:
case tok::kw___ptrauth:
+ case tok::kw___ptrauth_restricted_intptr:
case tok::kw__Nonnull:
case tok::kw__Nullable:
@@ -6584,6 +6588,7 @@ void Parser::ParseTypeQualifierListOpt(
// __ptrauth qualifier.
case tok::kw___ptrauth:
+ case tok::kw___ptrauth_restricted_intptr:
ParsePtrauthQualifier(DS.getAttributes());
EndLoc = PrevTokLocation;
continue;
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 14e16bc39eb3a..2881b6bb9bdd0 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -175,7 +175,7 @@ namespace {
// Destination type may not be qualified with __ptrauth.
if (DestType.getPointerAuth()) {
Self.Diag(DestRange.getBegin(), diag::err_ptrauth_qualifier_cast)
- << DestType << DestRange;
+ << DestType->isSignablePointerType() << DestType << DestRange;
}
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 97f623f61a405..b7794868e62e8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1551,7 +1551,8 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
return false;
}
-bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
+bool Sema::checkPointerAuthDiscriminatorArg(const AttributeCommonInfo &AttrInfo,
+ Expr *Arg,
PointerAuthDiscArgKind Kind,
unsigned &IntVal) {
if (!Arg) {
@@ -1560,8 +1561,9 @@ bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
}
std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context);
+ StringRef AttrName = AttrInfo.getAttrName()->getName();
if (!Result) {
- Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice);
+ Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice) << AttrName;
return false;
}
@@ -1581,10 +1583,10 @@ bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
if (*Result < 0 || *Result > Max) {
if (IsAddrDiscArg)
Diag(Arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid)
- << Result->getExtValue();
+ << Result->getExtValue() << AttrName;
else
Diag(Arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid)
- << Result->getExtValue() << Max;
+ << Result->getExtValue() << AttrName << Max;
return false;
};
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 63937ddc3e386..a13a494aa51fc 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15532,7 +15532,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// __ptrauth is forbidden on parameters.
if (T.getPointerAuth()) {
- Diag(NameLoc, diag::err_ptrauth_qualifier_invalid) << T << 1;
+ Diag(NameLoc, diag::err_ptrauth_qualifier_invalid)
+ << 1 << T->isSignablePointerType() << T;
New->setInvalidDecl();
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 22e21524c54be..2eaa260f67867 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -10615,7 +10615,7 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) {
return;
}
- // Ill-formed if the field is an address-discriminated pointer.
+ // Ill-formed if the field is an address-discriminated value.
if (FT.hasAddressDiscriminatedPointerAuth()) {
PrintDiagAndRemoveAttr(6);
return;
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index 3e962fcb8b0e5..9bd19befc6d5b 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -180,9 +180,9 @@ Decl *SemaObjC::ActOnProperty(Scope *S, SourceLocation AtLoc,
0);
TypeSourceInfo *TSI = SemaRef.GetTypeForDeclarator(FD.D);
QualType T = TSI->getType();
- if (T.getPointerAuth().isPresent()) {
- Diag(AtLoc, diag::err_ptrauth_qualifier_invalid) << T << 2;
- }
+ if (T.getPointerAuth().isPresent())
+ Diag(AtLoc, diag::err_ptrauth_qualifier_invalid)
+ << 2 << T->isSignablePointerType() << T;
if (!getOwnershipRule(Attributes)) {
Attributes |= deducePropertyOwnershipFromType(SemaRef, T);
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 294daef70c339..beda73d930886 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2552,9 +2552,10 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
return true;
}
- // __ptrauth is illegal on a function return type.
+ // __ptrauth[_restricted_intptr] is illegal on a function return type.
if (T.getPointerAuth()) {
- Diag(Loc, diag::err_ptrauth_qualifier_invalid) << T << 0;
+ Diag(Loc, diag::err_ptrauth_qualifier_invalid)
+ << 0 << T->isSignablePointerType() << T;
return true;
}
@@ -2664,8 +2665,9 @@ QualType Sema::BuildFunctionType(QualType T,
Diag(Loc, diag::err_wasm_table_as_function_parameter);
Invalid = true;
} else if (ParamType.getPointerAuth()) {
- // __ptrauth is illegal on a function return type.
- Diag(Loc, diag::err_ptrauth_qualifier_invalid) << T << 1;
+ // __ptrauth[_restricted_intptr] is illegal on a function return type.
+ Diag(Loc, diag::err_ptrauth_qualifier_invalid)
+ << 1 << T->isSignablePointerType() << T;
Invalid = true;
}
@@ -4986,7 +4988,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// __ptrauth is illegal on a function return type.
if (T.getPointerAuth()) {
- S.Diag(DeclType.Loc, diag::err_ptrauth_qualifier_invalid) << T << 0;
+ S.Diag(DeclType.Loc, diag::err_ptrauth_qualifier_invalid)
+ << 0 << T->isSignablePointerType() << T;
}
if (LangOpts.OpenCL) {
@@ -8353,6 +8356,7 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
assert((Attr.getNumArgs() > 0 && Attr.getNumArgs() <= 3) &&
"__ptrauth qualifier takes between 1 and 3 arguments");
+ StringRef AttrName = Attr.getAttrName()->getName();
Expr *KeyArg = Attr.getArgAsExpr(0);
Expr *IsAddressDiscriminatedArg =
Attr.getNumArgs() >= 2 ? Attr.getArgAsExpr(1) : nullptr;
@@ -8368,26 +8372,38 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
bool IsInvalid = false;
unsigned IsAddressDiscriminated, ExtraDiscriminator;
- IsInvalid |= !S.checkPointerAuthDiscriminatorArg(IsAddressDiscriminatedArg,
- PointerAuthDiscArgKind::Addr,
- IsAddressDiscriminated);
IsInvalid |= !S.checkPointerAuthDiscriminatorArg(
- ExtraDiscriminatorArg, PointerAuthDiscArgKind::Extra, ExtraDiscriminator);
+ Attr, IsAddressDiscriminatedArg, PointerAuthDiscArgKind::Addr,
+ IsAddressDiscriminated);
+ IsInvalid |= !S.checkPointerAuthDiscriminatorArg(Attr, ExtraDiscriminatorArg,
+ PointerAuthDiscArgKind::Extra,
+ ExtraDiscriminator);
if (IsInvalid) {
Attr.setInvalid();
return;
}
-
- if (!T->isSignableType() && !T->isDependentType()) {
- S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T;
- Attr.setInvalid();
- return;
+ bool IsRestrictedIntegral = false;
+ if (AttrName == "__ptrauth_restricted_intptr") {
+ IsRestrictedIntegral = true;
+ if (!T->isSignableIntegerType(Ctx) && !T->isDependentType()) {
+ S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_invalid_target)
+ << 0 << T;
+ Attr.setInvalid();
+ return;
+ }
+ } else {
+ if (!T->isSignablePointerType() && !T->isDependentType()) {
+ S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_invalid_target)
+ << 1 << T;
+ Attr.setInvalid();
+ return;
+ }
}
if (T.getPointerAuth()) {
S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant)
- << T << Attr.getAttrName()->getName();
+ << T << AttrName;
Attr.setInvalid();
return;
}
@@ -8402,7 +8418,8 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T,
"address discriminator arg should be either 0 or 1");
PointerAuthQualifier Qual = PointerAuthQualifier::Create(
Key, IsAddressDiscriminated, ExtraDiscriminator,
- PointerAuthenticationMode::SignAndAuth, false, false);
+ PointerAuthenticationMode::SignAndAuth, /*IsIsaPointer=*/false,
+ /*AuthenticatesNullValues=*/false, IsRestrictedIntegral);
T = S.Context.getPointerAuthType(T, Qual);
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index aed00e0ff06cd..53c8a265f1a71 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5292,12 +5292,25 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
if (LocalPointerAuth.isPresent()) {
if (T.getPointerAuth().isPresent()) {
SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_redundant)
- << TL.getType() << "__ptrauth";
- return QualType();
- } else if (!T->isSignableType() && !T->isDependentType()) {
- SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_nonpointer) << T;
+ << TL.getType()
+ << (LocalPointerAuth.isRestrictedIntegral()
+ ? "__ptrauth_restricted_intptr"
+ : "__ptrauth");
return QualType();
}
+ if (!T->isDependentType()) {
+ if (Quals.getPointerAuth().isRestrictedIntegral()) {
+ if (!T->isSignableIntegerType(SemaRef.getASTContext())) {
+ SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_invalid_target)
+ << /*IsPtrauth=*/0 << T;
+ return QualType();
+ }
+ } else if (!T->isSignablePointerType()) {
+ SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_invalid_target)
+ << /*IsPtrauth=*/1 << T;
+ return QualType();
+ }
+ }
}
// C++ [dcl.fct]p7:
// [When] adding cv-qualifications on top of the function type [...] the
diff --git a/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c b/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c
new file mode 100644
index 0000000000000..2667fb01ebcee
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-restricted-intptr-qualifier.c
@@ -0,0 +1,220 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -O0 -o - | FileCheck %s
+#if !__has_extension(ptrauth_restricted_intptr_qualifier)
+#error ptrauth_restricted_intptr_qualifier should exist
+#endif
+
+__INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 0, 56) g1 = 0;
+// CHECK: @g1 = global i64 0
+__INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 1272) g2 = 0;
+// CHECK: @g2 = global i64 0
+extern __UINTPTR_TYPE__ test_int;
+__UINTPTR_TYPE__ __ptrauth_restricted_intptr(3, 1, 23) g3 = (__UINTPTR_TYPE__)&test_int;
+// CHECK: @test_int = external global i64
+// CHECK: @g3 = global i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 3, i64 23, ptr @g3) to i64)
+
+__INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 712) ga[3] = {0,0,(__UINTPTR_TYPE__)&test_int};
+
+// CHECK: @ga = global [3 x i64] [i64 0, i64 0, i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 1, i64 712, ptr getelementptr inbounds ([3 x i64], ptr @ga, i32 0, i32 2)) to i64)]
+
+struct A {
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 0, 431) f0;
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 0, 9182) f1;
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 0, 783) f2;
+};
+
+struct A gs1 = {0, 0, (__UINTPTR_TYPE__)&test_int};
+// CHECK: @gs1 = global %struct.A { i64 0, i64 0, i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 1, i64 783) to i64) }
+
+struct B {
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 1276) f0;
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 23674) f1;
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 163) f2;
+};
+
+struct B gs2 = {0, 0, (__UINTPTR_TYPE__)&test_int};
+// CHECK: @gs2 = global %struct.B { i64 0, i64 0, i64 ptrtoint (ptr ptrauth (ptr @test_int, i32 1, i64 163, ptr getelementptr inbounds (%struct.B, ptr @gs2, i32 0, i32 2)) to i64) }
+
+// CHECK-LABEL: i64 @test_read_globals
+__INTPTR_TYPE__ test_read_globals() {
+ __INTPTR_TYPE__ result = g1 + g2 + g3;
+ // CHECK: [[A:%.*]] = load i64, ptr @g1
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[A]], i32 1, i64 56)
+ // CHECK: [[B:%.*]] = load i64, ptr @g2
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @g2 to i64), i64 1272)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[B]], i32 1, i64 [[BLENDED]])
+ // CHECK: [[VALUE:%.*]] = load i64, ptr @g3
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @g3 to i64), i64 23)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 3, i64 [[BLENDED]])
+
+ for (int i = 0; i < 3; i++) {
+ result += ga[i];
+ }
+ // CHECK: for.cond:
+ // CHECK: [[TEMP:%.*]] = load i32, ptr [[IDX_ADDR:%.*]]
+
+ // CHECK: for.body:
+ // CHECK: [[IDX:%.*]] = load i32, ptr [[IDX_ADDR]]
+ // CHECK: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
+ // CHECK: [[ARRAYIDX:%.*]] = getelementptr inbounds [3 x i64], ptr @ga, i64 0, i64 [[IDXPROM]]
+ // CHECK: [[VALUE:%.*]] = load i64, ptr [[ARRAYIDX]]
+ // CHECK: [[CASTIDX:%.*]] = ptrtoint ptr [[ARRAYIDX]] to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTIDX]], i64 712)
+ // CHECK: resign.nonnull6:
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]])
+ // CHECK: resign.cont7
+
+ result += gs1.f0 + gs1.f1 + gs1.f2;
+ // CHECK: resign.cont10:
+ // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.A, ptr @gs1, i32 0, i32 1
+ // CHECK: resign.nonnull11:
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 9182)
+ // CHECK: resign.cont12:
+ // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.A, ptr @gs1, i32 0, i32 2)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 783)
+ result += gs2.f0 + gs2.f1 + gs2.f2;
+ // CHECK: [[ADDR:%.*]] = load i64, ptr @gs2
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @gs2 to i64), i64 1276)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 [[BLENDED]])
+ // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 1)
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 1) to i64), i64 23674)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[ADDR]], i32 1, i64 [[BLENDED]])
+ // CHECK: [[ADDR:%.*]] = load i64, ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 2)
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds nuw (%struct.B, ptr @gs2, i32 0, i32 2) to i64), i64 163)
+
+ return result;
+}
+
+// CHECK-LABEL: void @test_write_globals
+void test_write_globals(int i, __INTPTR_TYPE__ j) {
+ g1 = i;
+ g2 = j;
+ g3 = 0;
+ ga[0] = i;
+ ga[1] = j;
+ ga[2] = 0;
+ gs1.f0 = i;
+ gs1.f1 = j;
+ gs1.f2 = 0;
+ gs2.f0 = i;
+ gs2.f1 = j;
+ gs2.f2 = 0;
+}
+
+// CHECK-LABEL: define void @test_set_A
+void test_set_A(struct A *a, __INTPTR_TYPE__ x, int y) {
+ a->f0 = x;
+ // CHECK: [[XADDR:%.*]] = load i64, ptr %x.addr
+ // CHECK: [[SIGNED_X:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[XADDR]], i32 1, i64 431)
+ a->f1 = y;
+ // CHECK: [[Y:%.*]] = load i32, ptr %y.addr
+ // CHECK: [[CONV:%.*]] = sext i32 [[Y]] to i64
+ // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CONV]], i32 1, i64 9182)
+ a->f2 = 0;
+ // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+ // CHECK: [[F2:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 2
+ // CHECK: store i64 0, ptr [[F2]]
+}
+
+// CHECK-LABEL: define void @test_set_B
+void test_set_B(struct B *b, __INTPTR_TYPE__ x, int y) {
+ b->f0 = x;
+ // CHECK: [[X:%.*]] = load i64, ptr %x.addr
+ // CHECK: [[F0_ADDR:%.*]] = ptrtoint ptr %f0 to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[F0_ADDR]], i64 1276)
+ // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[X]], i32 1, i64 [[BLENDED]])
+ b->f1 = y;
+ // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+ // CHECK: [[F1_ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 1
+ // CHECK: [[Y:%.*]] = load i32, ptr %y.addr, align 4
+ // CHECK: [[CONV:%.*]] = sext i32 [[Y]] to i64
+ // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[F1_ADDR]] to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 23674)
+ // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[CONV]], i32 1, i64 [[BLENDED]])
+ b->f2 = 0;
+ // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+ // CHECK: [[F2_ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 2
+ // CHECK: store i64 0, ptr [[F2_ADDR]]
+}
+
+// CHECK-LABEL: define i64 @test_get_A
+__INTPTR_TYPE__ test_get_A(struct A *a) {
+ return a->f0 + a->f1 + a->f2;
+ // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+ // CHECK: [[F0_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 0
+ // CHECK: [[F0:%.*]] = load i64, ptr [[F0_ADDR]]
+ // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F0]], i32 1, i64 431)
+ // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+ // CHECK: [[F1_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 1
+ // CHECK: [[F1:%.*]] = load i64, ptr [[F1_ADDR]]
+ // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F1]], i32 1, i64 9182)
+ // CHECK: [[A:%.*]] = load ptr, ptr %a.addr
+ // CHECK: [[F2_ADDR:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 2
+ // CHECK: [[F2:%.*]] = load i64, ptr [[F2_ADDR]]
+ // CHECK: [[AUTH:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[F2]], i32 1, i64 783)
+}
+
+// CHECK-LABEL: define i64 @test_get_B
+__INTPTR_TYPE__ test_get_B(struct B *b) {
+ return b->f0 + b->f1 + b->f2;
+ // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+ // CHECK: [[F0:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 0
+ // CHECK: [[VALUE:%.*]] = load i64, ptr [[F0]]
+ // CHECK: [[CASTF0:%.*]] = ptrtoint ptr %f0 to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTF0]], i64 1276)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]])
+ // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+ // CHECK: [[ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 1
+ // CHECK: [[VALUE:%.*]] = load i64, ptr [[ADDR]]
+ // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 23674)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]])
+ // CHECK: [[B:%.*]] = load ptr, ptr %b.addr
+ // CHECK: [[ADDR:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 2
+ // CHECK: [[VALUE:%.*]] = load i64, ptr [[ADDR]]
+ // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr [[ADDR]] to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 163)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]])
+}
+
+// CHECK-LABEL: define void @test_resign
+void test_resign(struct A* a, const struct B *b) {
+ a->f0 = b->f0;
+ // CHECK: [[A:%.*]] = load ptr, ptr %a.addr, align 8
+ // CHECK: [[F0:%.*]] = getelementptr inbounds nuw %struct.A, ptr [[A]], i32 0, i32 0
+ // CHECK: [[B:%.*]] = load ptr, ptr %b.addr, align 8
+ // CHECK: [[F01:%.*]] = getelementptr inbounds nuw %struct.B, ptr [[B]], i32 0, i32 0
+ // CHECK: [[F01VALUE:%.*]] = load i64, ptr [[F01]]
+ // CHECK: [[CASTF01:%.*]] = ptrtoint ptr %f01 to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTF01]], i64 1276)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[F01VALUE]], i32 1, i64 [[BLENDED]], i32 1, i64 431)
+}
+
+// CHECK-LABEL: define i64 @other_test
+__INTPTR_TYPE__ other_test(__INTPTR_TYPE__ i) {
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 42) j = 0;
+ // CHECK: [[J_ADDR:%.*]] = ptrtoint ptr %j to i64
+ // CHECK: store i64 0, ptr %j
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 43) k = 1234;
+ // CHECK: [[ADDR:%.*]] = ptrtoint ptr %k to i64
+ // CHECK: [[JBLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 43)
+ // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 1234, i32 1, i64 [[JBLENDED]])
+ __INTPTR_TYPE__ __ptrauth_restricted_intptr(1, 1, 44) l = i;
+ // CHECK: [[I:%.*]] = load i64, ptr %i.addr
+ // CHECK: [[ADDR:%.*]] = ptrtoint ptr %l to i64
+ // CHECK: [[LBLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 44)
+ // CHECK: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[I]], i32 1, i64 [[LBLENDED]])
+ asm volatile ("" ::: "memory");
+ return j + k + l;
+ // CHECK: [[VALUE:%.*]] = load i64, ptr %j
+ // CHECK: [[CAST_ADDR:%.*]] = ptrtoint ptr %j to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CAST_ADDR]], i64 42)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]])
+ // CHECK: [[VALUE:%.*]] = load i64, ptr %k
+ // CHECK: [[CASTK:%.*]] = ptrtoint ptr %k to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTK]], i64 43)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]])
+ // CHECK: [[VALUE:%.*]] = load i64, ptr %l
+ // CHECK: [[CASTL:%.*]] = ptrtoint ptr %l to i64
+ // CHECK: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[CASTL]], i64 44)
+ // CHECK: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VALUE]], i32 1, i64 [[BLENDED]])
+}
diff --git a/clang/test/Sema/ptrauth-restricted-intptr-qualifier.c b/clang/test/Sema/ptrauth-restricted-intptr-qualifier.c
new file mode 100644
index 0000000000000..a73aab7bd73c0
--- /dev/null
+++ b/clang/test/Sema/ptrauth-restricted-intptr-qualifier.c
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s
+#if !__has_extension(ptrauth_restricted_intptr_qualifier)
+#error ptrauth_restricted_intptr_qualifier should exist
+#endif
+
+int *__ptrauth_restricted_intptr(0) a;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'int *' is invalid}}
+
+char __ptrauth_restricted_intptr(0) b;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'char' is invalid}}
+unsigned char __ptrauth_restricted_intptr(0) c;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'unsigned char' is invalid}}
+short __ptrauth_restricted_intptr(0) d;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'short' is invalid}}
+unsigned short __ptrauth_restricted_intptr(0) e;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'unsigned short' is invalid}}
+int __ptrauth_restricted_intptr(0) f;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'int' is invalid}}
+unsigned int __ptrauth_restricted_intptr(0) g;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'unsigned int' is invalid}}
+__int128_t __ptrauth_restricted_intptr(0) h;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; '__int128_t' (aka '__int128') is invalid}}
+unsigned short __ptrauth_restricted_intptr(0) i;
+// expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'unsigned short' is invalid}}
+
+unsigned long long __ptrauth_restricted_intptr(0) j;
+long long __ptrauth_restricted_intptr(0) k;
+__SIZE_TYPE__ __ptrauth_restricted_intptr(0) l;
+const unsigned long long __ptrauth_restricted_intptr(0) m;
+const long long __ptrauth_restricted_intptr(0) n;
+const __SIZE_TYPE__ __ptrauth_restricted_intptr(0) o;
+
+struct S1 {
+ __SIZE_TYPE__ __ptrauth_restricted_intptr(0) f0;
+};
+struct S2 {
+ int *__ptrauth_restricted_intptr(0) f0;
+ // expected-error at -1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'int *' is invalid}}
+};
+
+void x(unsigned long long __ptrauth_restricted_intptr(0) f0);
+// expected-error at -1{{parameter type may not be qualified with '__ptrauth_restricted_intptr'; type is '__ptrauth_restricted_intptr(0,0,0) unsigned long long'}}
+
+unsigned long long __ptrauth_restricted_intptr(0) y();
+// expected-error at -1{{return type may not be qualified with '__ptrauth_restricted_intptr'; type is '__ptrauth_restricted_intptr(0,0,0) unsigned long long'}}
diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp b/clang/test/SemaCXX/ptrauth-triviality.cpp
index baadadca9f64f..08407d4cdeb1f 100644
--- a/clang/test/SemaCXX/ptrauth-triviality.cpp
+++ b/clang/test/SemaCXX/ptrauth-triviality.cpp
@@ -4,6 +4,8 @@
#define AQ __ptrauth(1,1,50)
#define IQ __ptrauth(1,0,50)
+#define AQ_IP __ptrauth_restricted_intptr(1,1,50)
+#define IQ_IP __ptrauth_restricted_intptr(1,0,50)
#define AA [[clang::ptrauth_vtable_pointer(process_independent,address_discrimination,no_extra_discrimination)]]
#define IA [[clang::ptrauth_vtable_pointer(process_independent,no_address_discrimination,type_discrimination)]]
#define PA [[clang::ptrauth_vtable_pointer(process_dependent,no_address_discrimination,no_extra_discrimination)]]
@@ -121,3 +123,45 @@ static_assert(__is_trivially_destructible(Holder<S5>));
static_assert(!__is_trivially_copyable(Holder<S5>));
static_assert(!__is_trivially_relocatable(Holder<S5>));
static_assert(!__is_trivially_equality_comparable(Holder<S5>));
+
+struct S6 {
+ __INTPTR_TYPE__ AQ_IP p_;
+ void *payload_;
+ bool operator==(const S6&) const = default;
+};
+static_assert(__is_trivially_constructible(S6));
+static_assert(!__is_trivially_constructible(S6, const S6&));
+static_assert(!__is_trivially_assignable(S6, const S6&));
+static_assert(__is_trivially_destructible(S6));
+static_assert(!__is_trivially_copyable(S6));
+static_assert(!__is_trivially_relocatable(S6));
+static_assert(!__is_trivially_equality_comparable(S6));
+
+static_assert(__is_trivially_constructible(Holder<S6>));
+static_assert(!__is_trivially_constructible(Holder<S6>, const Holder<S6>&));
+static_assert(!__is_trivially_assignable(Holder<S6>, const Holder<S6>&));
+static_assert(__is_trivially_destructible(Holder<S6>));
+static_assert(!__is_trivially_copyable(Holder<S6>));
+static_assert(!__is_trivially_relocatable(Holder<S6>));
+static_assert(!__is_trivially_equality_comparable(Holder<S6>));
+
+struct S7 {
+ __INTPTR_TYPE__ IQ_IP p_;
+ void *payload_;
+ bool operator==(const S7&) const = default;
+};
+static_assert(__is_trivially_constructible(S7));
+static_assert(__is_trivially_constructible(S7, const S7&));
+static_assert(__is_trivially_assignable(S7&, const S7&));
+static_assert(__is_trivially_destructible(S7));
+static_assert(__is_trivially_copyable(S7));
+static_assert(__is_trivially_relocatable(S7));
+static_assert(__is_trivially_equality_comparable(S7));
+
+static_assert(__is_trivially_constructible(Holder<S7>));
+static_assert(__is_trivially_constructible(Holder<S7>, const Holder<S7>&));
+static_assert(__is_trivially_assignable(Holder<S7>, const Holder<S7>&));
+static_assert(__is_trivially_destructible(Holder<S7>));
+static_assert(__is_trivially_copyable(Holder<S7>));
+static_assert(__is_trivially_relocatable(Holder<S7>));
+static_assert(__is_trivially_equality_comparable(Holder<S7>));
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index a3e809f44ed23..b572a48316efb 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -642,6 +642,11 @@ static TypePayloadClang GetPtrAuthMofidierPayload(const DWARFDIE &die) {
auto getAttr = [&](llvm::dwarf::Attribute Attr, unsigned defaultValue = 0) {
return die.GetAttributeValueAsUnsigned(Attr, defaultValue);
};
+ bool is_restricted_integral = false;
+ if (Type *res_type = die.GetDWARF()->ResolveType(die))
+ if (auto *ptr_type = (clang::Type *)res_type->GetForwardCompilerType()
+ .GetOpaqueQualType())
+ is_restricted_integral = !ptr_type->isPointerType();
const unsigned key = getAttr(DW_AT_LLVM_ptrauth_key);
const bool addr_disc = getAttr(DW_AT_LLVM_ptrauth_address_discriminated);
const unsigned extra = getAttr(DW_AT_LLVM_ptrauth_extra_discriminator);
@@ -667,7 +672,7 @@ static TypePayloadClang GetPtrAuthMofidierPayload(const DWARFDIE &die) {
}
auto ptr_auth = clang::PointerAuthQualifier::Create(
key, addr_disc, extra, authentication_mode, isapointer,
- authenticates_null_values);
+ authenticates_null_values, is_restricted_integral);
return TypePayloadClang(ptr_auth.getAsOpaqueValue());
}
More information about the cfe-commits
mailing list