Skip to content

Commit 0129e28

Browse files
committed
[clang] Add __ptrauth_restricted_intptr qualifier
__ptrauth_restricted_intptr provides a mechanism to apply pointer authentication to pointer sized integer types.
1 parent e17f07c commit 0129e28

26 files changed

+491
-76
lines changed

clang/docs/PointerAuthentication.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,20 @@ a discriminator determined as follows:
326326
is ``ptrauth_blend_discriminator(&x, discriminator)``; see
327327
`ptrauth_blend_discriminator`_.
328328

329+
__ptrauth_restricted_intptr qualifier
330+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
331+
This is a variant of the ``__ptrauth`` qualifier, that applies to pointer sized
332+
integers. See the documentation for ``__ptrauth qualifier``.
333+
334+
This feature exists to support older APIs that use [u]intptrs to hold opaque
335+
pointer types.
336+
337+
Care must be taken to avoid using the signature bit components of the signed
338+
integers or subsequent authentication of the signed value may fail.
339+
340+
Note: When applied to a global initialiser a signed uintptr can only be
341+
initialised with the value 0 or a global address.
342+
329343
``<ptrauth.h>``
330344
~~~~~~~~~~~~~~~
331345

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ Arm and AArch64 Support
608608
ARM targets, however this will now disable NEON instructions being generated. The ``simd`` option is
609609
also now printed when the ``--print-supported-extensions`` option is used.
610610

611-
- Support for __ptrauth type qualifier has been added.
611+
- Support for __ptrauth and __ptrauth_restricted_intptr type qualifiers has been added.
612612

613613
- For AArch64, added support for generating executable-only code sections by using the
614614
``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688)

clang/include/clang/AST/Type.h

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,13 @@ class PointerAuthQualifier {
168168
AuthenticatesNullValuesBits = 1,
169169
AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1)
170170
<< AuthenticatesNullValuesShift,
171-
KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
172-
KeyBits = 10,
171+
RestrictedIntegralShift =
172+
AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
173+
RestrictedIntegralBits = 1,
174+
RestrictedIntegralMask = ((1 << RestrictedIntegralBits) - 1)
175+
<< RestrictedIntegralShift,
176+
KeyShift = RestrictedIntegralShift + RestrictedIntegralBits,
177+
KeyBits = 9,
173178
KeyMask = ((1 << KeyBits) - 1) << KeyShift,
174179
DiscriminatorShift = KeyShift + KeyBits,
175180
DiscriminatorBits = 16,
@@ -178,32 +183,33 @@ class PointerAuthQualifier {
178183

179184
// bits: |0 |1 |2..3 |4 |
180185
// |Enabled|Address|AuthenticationMode|ISA pointer|
181-
// bits: |5 |6..15| 16...31 |
182-
// |AuthenticatesNull|Key |Discriminator|
186+
// bits: |5 |6 |7..15| 16...31 |
187+
// |AuthenticatesNull|RestrictedIntegral|Key |Discriminator|
183188
uint32_t Data = 0;
184189

185190
// The following static assertions check that each of the 32 bits is present
186191
// exactly in one of the constants.
187192
static_assert((EnabledBits + AddressDiscriminatedBits +
188193
AuthenticationModeBits + IsaPointerBits +
189-
AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) ==
190-
32,
194+
AuthenticatesNullValuesBits + RestrictedIntegralBits +
195+
KeyBits + DiscriminatorBits) == 32,
191196
"PointerAuthQualifier should be exactly 32 bits");
192197
static_assert((EnabledMask + AddressDiscriminatedMask +
193198
AuthenticationModeMask + IsaPointerMask +
194-
AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) ==
195-
0xFFFFFFFF,
199+
AuthenticatesNullValuesMask + RestrictedIntegralMask +
200+
KeyMask + DiscriminatorMask) == 0xFFFFFFFF,
196201
"All masks should cover the entire bits");
197202
static_assert((EnabledMask ^ AddressDiscriminatedMask ^
198203
AuthenticationModeMask ^ IsaPointerMask ^
199-
AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) ==
200-
0xFFFFFFFF,
204+
AuthenticatesNullValuesMask ^ RestrictedIntegralMask ^
205+
KeyMask ^ DiscriminatorMask) == 0xFFFFFFFF,
201206
"All masks should cover the entire bits");
202207

203208
PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated,
204209
unsigned ExtraDiscriminator,
205210
PointerAuthenticationMode AuthenticationMode,
206-
bool IsIsaPointer, bool AuthenticatesNullValues)
211+
bool IsIsaPointer, bool AuthenticatesNullValues,
212+
bool IsRestrictedIntegral)
207213
: Data(EnabledMask |
208214
(IsAddressDiscriminated
209215
? llvm::to_underlying(AddressDiscriminatedMask)
@@ -212,8 +218,8 @@ class PointerAuthQualifier {
212218
(llvm::to_underlying(AuthenticationMode)
213219
<< AuthenticationModeShift) |
214220
(ExtraDiscriminator << DiscriminatorShift) |
215-
(IsIsaPointer << IsaPointerShift) |
216-
(AuthenticatesNullValues << AuthenticatesNullValuesShift)) {
221+
(AuthenticatesNullValues << AuthenticatesNullValuesShift) |
222+
(IsRestrictedIntegral << RestrictedIntegralShift)) {
217223
assert(Key <= KeyNoneInternal);
218224
assert(ExtraDiscriminator <= MaxDiscriminator);
219225
assert((Data == 0) ==
@@ -237,13 +243,13 @@ class PointerAuthQualifier {
237243
static PointerAuthQualifier
238244
Create(unsigned Key, bool IsAddressDiscriminated, unsigned ExtraDiscriminator,
239245
PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer,
240-
bool AuthenticatesNullValues) {
246+
bool AuthenticatesNullValues, bool IsRestrictedIntegral) {
241247
if (Key == PointerAuthKeyNone)
242248
Key = KeyNoneInternal;
243249
assert(Key <= KeyNoneInternal && "out-of-range key value");
244250
return PointerAuthQualifier(Key, IsAddressDiscriminated, ExtraDiscriminator,
245251
AuthenticationMode, IsIsaPointer,
246-
AuthenticatesNullValues);
252+
AuthenticatesNullValues, IsRestrictedIntegral);
247253
}
248254

249255
bool isPresent() const {
@@ -290,6 +296,10 @@ class PointerAuthQualifier {
290296
return hasKeyNone() ? PointerAuthQualifier() : *this;
291297
}
292298

299+
bool isRestrictedIntegral() const {
300+
return (Data & RestrictedIntegralMask) >> RestrictedIntegralShift;
301+
}
302+
293303
friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
294304
return Lhs.Data == Rhs.Data;
295305
}
@@ -2563,7 +2573,9 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
25632573
bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
25642574
bool isPointerType() const;
25652575
bool isPointerOrReferenceType() const;
2566-
bool isSignableType() const;
2576+
bool isSignableType(const ASTContext &Ctx) const;
2577+
bool isSignablePointerType() const;
2578+
bool isSignableIntegerType(const ASTContext &Ctx) const;
25672579
bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
25682580
bool isCountAttributedType() const;
25692581
bool isBlockPointerType() const;
@@ -8216,7 +8228,13 @@ inline bool Type::isAnyPointerType() const {
82168228
return isPointerType() || isObjCObjectPointerType();
82178229
}
82188230

8219-
inline bool Type::isSignableType() const { return isPointerType(); }
8231+
inline bool Type::isSignableType(const ASTContext &Ctx) const {
8232+
return isSignablePointerType() || isSignableIntegerType(Ctx);
8233+
}
8234+
8235+
inline bool Type::isSignablePointerType() const {
8236+
return isPointerType() || isObjCClassType() || isObjCQualifiedClassType();
8237+
}
82208238

82218239
inline bool Type::isBlockPointerType() const {
82228240
return isa<BlockPointerType>(CanonicalType);

clang/include/clang/Basic/Attr.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3578,7 +3578,8 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
35783578
}
35793579

35803580
def PointerAuth : TypeAttr {
3581-
let Spellings = [CustomKeyword<"__ptrauth">];
3581+
let Spellings = [CustomKeyword<"__ptrauth">,
3582+
CustomKeyword<"__ptrauth_restricted_intptr">];
35823583
let Args = [IntArgument<"Key">,
35833584
BoolArgument<"AddressDiscriminated", 1>,
35843585
IntArgument<"ExtraDiscriminator", 1>];

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,20 +1021,27 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error<
10211021
"supported with ptrauth indirect gotos">;
10221022

10231023
// __ptrauth qualifier
1024-
def err_ptrauth_qualifier_invalid : Error<
1025-
"%select{return type|parameter type|property}1 may not be qualified with '__ptrauth'; type is %0">;
1026-
def err_ptrauth_qualifier_cast : Error<
1027-
"cannot cast to '__ptrauth'-qualified type %0">;
1028-
def err_ptrauth_qualifier_nonpointer : Error<
1029-
"'__ptrauth' qualifier only applies to pointer types; %0 is invalid">;
1024+
def err_ptrauth_qualifier_invalid
1025+
: Error<
1026+
"%select{return type|parameter type|property}0 may not be qualified "
1027+
"with '%select{__ptrauth_restricted_intptr|__ptrauth}1'; type is %2">;
1028+
def err_ptrauth_qualifier_cast : Error<"cannot cast to "
1029+
"'%select{__ptrauth_restricted_intptr|__"
1030+
"ptrauth}0'-qualified type %1">;
1031+
def err_ptrauth_qualifier_invalid_target
1032+
: Error<"'%select{__ptrauth_restricted_intptr|__ptrauth}0' qualifier only "
1033+
"applies to %select{pointer sized integer|pointer}0 types; %1 is "
1034+
"invalid">;
10301035
def err_ptrauth_qualifier_redundant : Error<
10311036
"type %0 is already %1-qualified">;
1032-
def err_ptrauth_arg_not_ice : Error<
1033-
"argument to '__ptrauth' must be an integer constant expression">;
1034-
def err_ptrauth_address_discrimination_invalid : Error<
1035-
"invalid address discrimination flag '%0'; '__ptrauth' requires '0' or '1'">;
1036-
def err_ptrauth_extra_discriminator_invalid : Error<
1037-
"invalid extra discriminator flag '%0'; '__ptrauth' requires a value between '0' and '%1'">;
1037+
def err_ptrauth_arg_not_ice
1038+
: Error<"argument to '%0' must be an integer constant expression">;
1039+
def err_ptrauth_address_discrimination_invalid
1040+
: Error<
1041+
"invalid address discrimination flag '%0'; '%1' requires '0' or '1'">;
1042+
def err_ptrauth_extra_discriminator_invalid
1043+
: Error<"invalid extra discriminator flag '%0'; '%1' requires a value "
1044+
"between '0' and '%2'">;
10381045

10391046
/// main()
10401047
// static main() is not an error in C, just in C++.

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
108108
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
109109
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
110110
EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics)
111+
EXTENSION(ptrauth_restricted_intptr_qualifier, LangOpts.PointerAuthIntrinsics)
111112
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
112113
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
113114
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ KEYWORD(__func__ , KEYALL)
349349
KEYWORD(__objc_yes , KEYALL)
350350
KEYWORD(__objc_no , KEYALL)
351351
KEYWORD(__ptrauth , KEYALL)
352+
KEYWORD(__ptrauth_restricted_intptr , KEYALL)
352353

353354
// C2y
354355
UNARY_EXPR_OR_TYPE_TRAIT(_Countof, CountOf, KEYNOCXX)

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3599,7 +3599,8 @@ class Sema final : public SemaBase {
35993599
PADAK_ExtraDiscPtrAuth,
36003600
};
36013601

3602-
bool checkPointerAuthDiscriminatorArg(Expr *Arg, PointerAuthDiscArgKind Kind,
3602+
bool checkPointerAuthDiscriminatorArg(const AttributeCommonInfo &AttrInfo,
3603+
Expr *Arg, PointerAuthDiscArgKind Kind,
36033604
unsigned &IntVal);
36043605

36053606
/// Diagnose function specifiers on a declaration of an identifier that

clang/lib/AST/ASTContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,6 +2924,9 @@ bool ASTContext::hasUniqueObjectRepresentations(
29242924

29252925
// All integrals and enums are unique.
29262926
if (Ty->isIntegralOrEnumerationType()) {
2927+
// Address discriminated __ptrauth_restricted_intptr types are not unique
2928+
if (Ty.hasAddressDiscriminatedPointerAuth())
2929+
return false;
29272930
// Except _BitInt types that have padding bits.
29282931
if (const auto *BIT = Ty->getAs<BitIntType>())
29292932
return getTypeSize(BIT) == BIT->getNumBits();

clang/lib/AST/Type.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5056,6 +5056,12 @@ AttributedType::stripOuterNullability(QualType &T) {
50565056
return std::nullopt;
50575057
}
50585058

5059+
bool Type::isSignableIntegerType(const ASTContext &Ctx) const {
5060+
if (!isIntegralType(Ctx) || isEnumeralType())
5061+
return false;
5062+
return Ctx.getTypeSize(this) == Ctx.getTypeSize(Ctx.VoidPtrTy);
5063+
}
5064+
50595065
bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const {
50605066
const auto *objcPtr = getAs<ObjCObjectPointerType>();
50615067
if (!objcPtr)

0 commit comments

Comments
 (0)