https://github.com/ojhunt created https://github.com/llvm/llvm-project/pull/137580
__ptrauth_restricted_intptr provides a mechanism to apply pointer authentication to pointer sized integer types. >From 7af378bbec4c7cf3896f6f7bc95d816e398930f2 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@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 | 3 + 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 | 11 +- clang/lib/Sema/SemaDecl.cpp | 3 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaObjCProperty.cpp | 6 +- clang/lib/Sema/SemaType.cpp | 43 ++-- 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, 487 insertions(+), 74 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 eb2e8f2b8a6c0..fe9badf7ba97a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -608,7 +608,7 @@ Arm and AArch64 Support ARM targets, however this will now disable NEON instructions being generated. The ``simd`` option is also now printed when the ``--print-supported-extensions`` option is used. -- 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..6516c976e66c5 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 dcdcff8c46fe2..50bfe76a86619 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 4c96142e28134..79e26ff9293f0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1021,20 +1021,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 868e851342eb8..85c0f58181c98 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 0c77c5b5ca30a..e438194230cf7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3599,7 +3599,8 @@ class Sema final : public SemaBase { PADAK_ExtraDiscPtrAuth, }; - 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 c95e733f30494..73051f46444f8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2924,6 +2924,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 111a642173418..4bf4a02d47fbd 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5056,6 +5056,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..d196e39ea374c 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2444,6 +2444,9 @@ 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 8dbbcdaef25d8..ff84e3c3f87e9 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 69d40baaf4298..4db4c8670cc31 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3401,11 +3401,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(); @@ -4308,6 +4309,7 @@ void Parser::ParseDeclarationSpecifiers( // __ptrauth qualifier. case tok::kw___ptrauth: + case tok::kw___ptrauth_restricted_intptr: ParsePtrauthQualifier(DS.getAttributes()); continue; @@ -6025,6 +6027,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: @@ -6315,6 +6318,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: @@ -6581,6 +6585,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 9c9372d9ee2b0..561f6309de226 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1550,7 +1550,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) { @@ -1559,8 +1560,10 @@ 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; } @@ -1580,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 b0ebf3e5f47c3..e4c5f1b3aae00 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15472,7 +15472,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 d4e48a14d13c2..3b896e3518989 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10621,7 +10621,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 6e7ee8b5506ff..d22517be9d799 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,37 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, bool IsInvalid = false; unsigned IsAddressDiscriminated, ExtraDiscriminator; - IsInvalid |= !S.checkPointerAuthDiscriminatorArg(IsAddressDiscriminatedArg, + IsInvalid |= !S.checkPointerAuthDiscriminatorArg(Attr, IsAddressDiscriminatedArg, Sema::PADAK_AddrDiscPtrAuth, IsAddressDiscriminated); - IsInvalid |= !S.checkPointerAuthDiscriminatorArg( + IsInvalid |= !S.checkPointerAuthDiscriminatorArg(Attr, ExtraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, 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 +8417,7 @@ 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 5e83f83603335..805f4bcc1a496 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@-1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'int *' is invalid}} + +char __ptrauth_restricted_intptr(0) b; +// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'char' is invalid}} +unsigned char __ptrauth_restricted_intptr(0) c; +// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'unsigned char' is invalid}} +short __ptrauth_restricted_intptr(0) d; +// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'short' is invalid}} +unsigned short __ptrauth_restricted_intptr(0) e; +// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'unsigned short' is invalid}} +int __ptrauth_restricted_intptr(0) f; +// expected-error@-1{{'__ptrauth_restricted_intptr' qualifier only applies to pointer sized integer types; 'int' is invalid}} +unsigned int __ptrauth_restricted_intptr(0) g; +// expected-error@-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@-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@-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@-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@-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@-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 f22fcbab557a0..39c9f0fab923f 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()); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits