From 51c21ae0348b2ddb1b55f3ef9f74c2c36f4d21ae Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 26 Jul 2024 09:32:07 -0700 Subject: [PATCH 01/19] [PAC] Add support for __ptrauth type qualifier The qualifier allows programmer to directly control how pointers are signed when they are stored in a particular variable. The qualifier takes three arguments: the signing key, a flag specifying whether address discrimination should be used, and a non-negative integer that is used for additional discrimination. ``` typedef void (*my_callback)(const void*); my_callback __ptrauth(ptrauth_key_process_dependent_code, 1, 0xe27a) callback; ``` Co-Authored-By: John McCall rjmccall@apple.com --- clang/include/clang/AST/Type.h | 21 +- clang/include/clang/Basic/Attr.td | 8 + clang/include/clang/Basic/AttrDocs.td | 146 ++++ .../clang/Basic/DiagnosticSemaKinds.td | 46 +- clang/include/clang/Basic/Features.def | 1 + clang/include/clang/Basic/TokenKinds.def | 1 + clang/include/clang/Parse/Parser.h | 2 + clang/include/clang/Sema/Sema.h | 11 + clang/lib/AST/ASTContext.cpp | 1 + clang/lib/AST/DeclCXX.cpp | 27 + clang/lib/AST/ItaniumMangle.cpp | 20 + clang/lib/AST/TypePrinter.cpp | 40 + clang/lib/CodeGen/CGClass.cpp | 3 + clang/lib/CodeGen/CGDebugInfo.cpp | 19 +- clang/lib/CodeGen/CGDecl.cpp | 8 +- clang/lib/CodeGen/CGExpr.cpp | 48 ++ clang/lib/CodeGen/CGExprConstant.cpp | 27 +- clang/lib/CodeGen/CGExprScalar.cpp | 67 ++ clang/lib/CodeGen/CGPointerAuth.cpp | 140 ++++ clang/lib/CodeGen/CodeGenFunction.h | 20 + clang/lib/Parse/ParseDecl.cpp | 47 ++ clang/lib/Sema/SemaCast.cpp | 16 +- clang/lib/Sema/SemaChecking.cpp | 63 ++ clang/lib/Sema/SemaDecl.cpp | 14 +- clang/lib/Sema/SemaDeclCXX.cpp | 37 + clang/lib/Sema/SemaExpr.cpp | 14 + clang/lib/Sema/SemaExprCXX.cpp | 5 + clang/lib/Sema/SemaObjCProperty.cpp | 4 + clang/lib/Sema/SemaOverload.cpp | 11 + clang/lib/Sema/SemaType.cpp | 87 ++ clang/lib/Sema/TreeTransform.h | 11 + clang/test/CodeGen/ptrauth-debuginfo.c | 32 + .../test/CodeGen/ptrauth-qualifier-function.c | 75 ++ .../CodeGen/ptrauth-qualifier-loadstore.c | 744 ++++++++++++++++++ clang/test/CodeGen/ptrauth-qualifier.c | 87 ++ .../CodeGenCXX/ptrauth-qualifier-struct.cpp | 167 ++++ .../CodeGenObjCXX/ptrauth-struct-cxx-abi.mm | 35 + clang/test/Preprocessor/ptrauth_feature.c | 10 + clang/test/Sema/atomic-ops-ptrauth.c | 117 +++ clang/test/Sema/ptrauth-qualifier.c | 84 ++ clang/test/SemaCXX/ptrauth-qualifier.cpp | 141 ++++ .../SemaCXX/ptrauth-template-parameters.cpp | 20 + clang/test/SemaObjC/ptrauth-qualifier.m | 55 ++ 43 files changed, 2518 insertions(+), 14 deletions(-) create mode 100644 clang/test/CodeGen/ptrauth-debuginfo.c create mode 100644 clang/test/CodeGen/ptrauth-qualifier-function.c create mode 100644 clang/test/CodeGen/ptrauth-qualifier-loadstore.c create mode 100644 clang/test/CodeGen/ptrauth-qualifier.c create mode 100644 clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp create mode 100644 clang/test/CodeGenObjCXX/ptrauth-struct-cxx-abi.mm create mode 100644 clang/test/Sema/atomic-ops-ptrauth.c create mode 100644 clang/test/Sema/ptrauth-qualifier.c create mode 100644 clang/test/SemaCXX/ptrauth-qualifier.cpp create mode 100644 clang/test/SemaCXX/ptrauth-template-parameters.cpp create mode 100644 clang/test/SemaObjC/ptrauth-qualifier.m diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 72723c7c56e07..b84d808410583 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -307,6 +307,12 @@ class PointerAuthQualifier { return Result; } + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const; + + bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; + void print(raw_ostream &OS, const PrintingPolicy &Policy) const; + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); } }; @@ -556,7 +562,7 @@ class Qualifiers { bool hasAddressSpace() const { return Mask & AddressSpaceMask; } LangAS getAddressSpace() const { - return static_cast(Mask >> AddressSpaceShift); + return static_cast((Mask & AddressSpaceMask) >> AddressSpaceShift); } bool hasTargetSpecificAddressSpace() const { return isTargetAddressSpace(getAddressSpace()); @@ -815,6 +821,9 @@ class Qualifiers { static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t), "PointerAuthQualifier must be 32 bits"); + static constexpr uint64_t PtrAuthShift = 32; + static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; + static constexpr uint64_t UMask = 0x8; static constexpr uint64_t UShift = 3; static constexpr uint64_t GCAttrMask = 0x30; @@ -822,10 +831,8 @@ class Qualifiers { static constexpr uint64_t LifetimeMask = 0x1C0; static constexpr uint64_t LifetimeShift = 6; static constexpr uint64_t AddressSpaceMask = - ~(CVRMask | UMask | GCAttrMask | LifetimeMask); + ~(CVRMask | UMask | GCAttrMask | LifetimeMask | PtrAuthMask); static constexpr uint64_t AddressSpaceShift = 9; - static constexpr uint64_t PtrAuthShift = 32; - static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; }; class QualifiersAndAtomic { @@ -1460,6 +1467,12 @@ class QualType { return getQualifiers().getPointerAuth(); } + bool hasAddressDiscriminatedPointerAuth() const { + if (auto ptrauth = getPointerAuth()) + return ptrauth.isAddressDiscriminated(); + return false; + } + enum PrimitiveDefaultInitializeKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4825979a974d2..f9b447e85707d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3339,6 +3339,14 @@ def ObjCRequiresPropertyDefs : InheritableAttr { let SimpleHandler = 1; } +def PointerAuth : TypeAttr { + let Spellings = [CustomKeyword<"__ptrauth">]; + let Args = [IntArgument<"Key">, + BoolArgument<"AddressDiscriminated", 1>, + IntArgument<"ExtraDiscriminator", 1>]; + let Documentation = [PtrAuthDocs]; +} + def Unused : InheritableAttr { let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, C23<"", "maybe_unused", 202106>]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 99738812c8157..547cb010ebc84 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1758,6 +1758,152 @@ Also see the documentation for `@available }]; } +def PtrAuthDocs : Documentation { + let Category = DocCatVariable; + let Heading = "__ptrauth, __ptrauth_restricted_intptr"; + let Content = [{ +The ``__ptrauth`` qualifier allows the programmer to directly control +how pointers are signed when they are stored in a particular variable. +This can be used to strengthen the default protections of pointer +authentication and make it more difficult for an attacker to escalate +an ability to alter memory into full control of a process. + +.. code-block:: c + + #include + + typedef void (*my_callback)(const void*); + my_callback __ptrauth(ptrauth_key_process_dependent_code, 1, 0xe27a) callback; + +The first argument to ``__ptrauth`` is the name of the signing key. +Valid key names for the target are defined in ````. + +On ARM64, there are four keys: + +- ``ptrauth_key_process_independent_data`` +- ``ptrauth_key_process_dependent_data`` +- ``ptrauth_key_process_independent_code`` +- ``ptrauth_key_process_dependent_code`` + +In general, prefer using a code key for function pointers and a data key +for object pointers. The ARM64 architecture allows loads and calls to +execute more efficiently when the pointer is signed with an appropriate +key. Using code keys only for function pointers also substantially lessens +the risk of creating a so-called "signing oracle" for function pointers; +see the general pointer authentication language documentation. + +Using a process-dependent key provides stronger protection against +cross-process attacks. However, it also inhibits certain memory +optimizations when a shared library is loaded into multiple processes. +Using a process-independent key also allows signed pointers to be passed +in shared memory. Note that even the process-independent keys may change +after a reboot, so signed values should never be serialized. + +The second argument to ``__ptrauth`` is a flag (0 or 1) specifying whether +the object should use address discrimination. If only one argument is +given, the flag defaults to 0. Address discrimination provides strong +protection against attacks which copy signed pointers around in memory. +An attacker cannot usefully copy an arbitrary signed pointer over an +address-discriminated object. Nor can a value taken from an +address-discriminated object be usefully copied over some other signed +pointer. However, it is more expensive to copy values from one +address-discriminated object to another, even if the other arguments to +``__ptrauth`` are the same, and it is not valid to copy them with +``memcpy``. It is also not valid to map memory containing an +address-discriminated object into different places in the address +space, e.g. with ``mmap``. + +The third argument to ``__ptrauth`` is a small non-negative integer +which allows additional discrimination between objects. Using a +unique extra discriminator provides strong protection against attacks +which work by substituting one signed value for another. For example, +an attacker cannot usefully overwrite an object with a pointer from an +object using a different extra discriminator; this protection is similar +to the protection offered by address discrimination. A unique extra +discriminator also protects against "slide" attacks where an attacker +alters a pointer instead of altering the memory that the pointer points to. +The extra discriminator must be a constant expression. On ARM64, +its value must be between 0 and 65535. If the argument is not provided, +the default value is 0. It is generally preferable not to use the value 0, +especially with the process-independent keys, as this combination is used +in various places in the standard language ABI. + +The type qualified by ``__ptrauth`` must be a pointer type. Currently +only C pointer types are allowed and not block pointers, Objective-C +object pointers, or C++ references. ``__ptrauth`` is parsed and interpreted +using the same language rules as qualifiers like ``const`` and ``volatile``. +For example: + +.. code-block:: c + + __ptrauth(...) int *ex0; /* invalid: qualifies 'int', which is not a pointer type */ + int * __ptrauth(...) ex1; /* valid: ex1 has qualified type */ + int * __ptrauth(...) *ex2; /* valid: ex2 is a pointer to a qualified object */ + + typedef int *intp; + __ptrauth(...) intp ex3; /* valid: ex3 has qualified type */ + intp __ptrauth(...) ex4; /* valid: means the exact same thing as ex3 */ + +If a ``__ptrauth``-qualified l-value of function pointer type is +used as the function operand of a call expression, the function pointer +will be authenticated "atomically" with the call, such that an attacker +will not be able to corrupt the destination of the call even in the +presence of undefined behavior. (That is, the compiler must not +leave an un-signed pointer that it will later unconditionally trust +in a place where it could be feasibly overwritten by an attacker, +such as the stack or a callee-save register during an intervening call. +The compiler is not required to protect against improbable attacks +such as corruption of the register file, as might occur with a +corrupted kernel. It also need not guard against jumps to an arbitrary +place in the instruction stream, since such jumps would require an +attacker to already fully control the PC.) + +If the ABI specifies that a pointer is always signed --- that is, +if the pointer is a function pointer and the target uses ABI function +pointer authentication --- then signing and authenticating it as part +of a load/store actually means resigning it to/from the standard ABI +signature schema. Similarly, if both operands of a simple assignment +operator are ``__ptrauth``-qualified, the pointer copied by the +assignment is resigned from the right-hand operand's schema to the +left-hand operand's schema. These resigning operations are also done +"atomically" in the same sense as above. + +As a final guarantee, if the right-hand operand of an assignment or +the expression used to initialize a ``__ptrauth``-qualified object is +a direct reference to an object or function (e.g. ``&my_var``), the +signing of that pointer is atomic with the evaluaton of the reference +in this same sense. + +Otherwise, there are no guarantees of atomicity, and it is the +programmer's responsibility to avoid allowing a store into a +``__ptrauth``-qualified object to create a potential "signing oracle" +which an attacker could use to sign an arbitrary pointer of their choice. +Such oracles are particularly problematic when the signing uses a code +key because the oracle could potentially be used to allow an attacker +to construct a validly-signed function pointer, v-table entry, or +return address that points to an arbitrary instruction, allowing them +to completely take over the PC. Programmers attempting to use +``__ptrauth`` to protect a data pointer, or to protect function pointers +on targets that do not use ABI function pointer authentication, should +aim to maintain a "chain of authentication" from initialization all +the way to the point at which the pointer is used. If this is infeasible, +they should consider using ``ptrauth_sign_generic_data`` instead. + +Types that are written in r-value positions, such as return types, +parameter types, and cast types, may not be ``__ptrauth``-qualified +at the outermost level. This may be supported in the future. + +In C++, the arguments to ``__ptrauth`` may not be instantiation-dependent. +This may be supported in the future. + +This feature may be tested for with ``__has_feature(ptrauth_qualifier)``. +It is enabled whenever the ``ptrauth`` intrinsics are enabled. + +```` provides predefined qualifiers for various language +features that implicitly use pointer authentication. + }]; +} + def ExternalSourceSymbolDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 810abe4f23e31..db07874ffcbbf 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -956,6 +956,25 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error< "%select{subtraction|addition}0 of address-of-label expressions is not " "supported with ptrauth indirect gotos">; +// __ptrauth qualifier +def err_ptrauth_qualifier_invalid : Error< + "%select{return types|parameter types|properties}2 may not be qualified with %select{__ptrauth|__ptrauth_restricted_intptr}1; type is %0">; +def err_ptrauth_qualifier_cast : Error< + "cast types may not be qualified with __ptrauth; type is %0">; +def err_ptrauth_qualifier_nonpointer : Error< + "__ptrauth qualifier may only be applied to pointer types; type here is %0">; +def err_ptrauth_qualifier_redundant : Error< + "type %0 is already %1-qualified">; +def err_ptrauth_qualifier_bad_arg_count : Error< + "%0 qualifier must take between 1 and 3 arguments">; +def err_ptrauth_arg_not_ice : Error< + "argument to __ptrauth must be an integer constant expression">; +def err_ptrauth_address_discrimination_invalid : Error< + "address discrimination flag for __ptrauth must be 0 or 1; value is %0">; +def err_ptrauth_extra_discriminator_invalid : Error< + "extra discriminator for __ptrauth must be between " + "0 and %1; value is %0">; + /// main() // static main() is not an error in C, just in C++. def warn_static_main : Warning<"'main' should not be declared static">, @@ -3870,7 +3889,8 @@ def note_cannot_use_trivial_abi_reason : Note< "its copy constructors and move constructors are all deleted|" "it is polymorphic|" "it has a base of a non-trivial class type|it has a virtual base|" - "it has a __weak field|it has a field of a non-trivial class type}1">; + "it has a __weak field|it has a field of a non-trivial class type|" + "it has an address-discriminated __ptrauth field}1">; // Availability attribute def warn_availability_unknown_platform : Warning< @@ -4927,6 +4947,10 @@ def note_ovl_candidate_bad_ownership : Note< "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}4 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" "__autoreleasing}5 ownership">; +def note_ovl_candidate_bad_ptrauth : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%ordinal8 argument (%3) has %select{no ptrauth|%5}4 qualifier," + " but parameter has %select{no ptrauth|%7}6 qualifier">; def note_ovl_candidate_bad_cvr_this : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "'this' argument has type %3, but method is not marked " @@ -6005,7 +6029,7 @@ def note_deleted_special_member_class_subobject : Note< "%select{default|corresponding|default|default|default}4 constructor}0|" "destructor}5" "%select{||s||}4" - "|is an ObjC pointer}6">; + "|is an ObjC pointer|has an address-discriminated ptrauth qualifier}6">; def note_deleted_default_ctor_uninit_field : Note< "%select{default constructor of|constructor inherited by}0 " "%1 is implicitly deleted because field %2 of " @@ -8811,6 +8835,19 @@ def err_typecheck_incompatible_ownership : Error< "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " changes retain/release properties of pointer">; +def err_typecheck_incompatible_ptrauth : Error< + "%select{%diff{assigning $ to $|assigning to different types}1,0" + "|%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1" + "|%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1" + "|%diff{converting $ to type $|converting between types}0,1" + "|%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1" + "|%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1" + "|%diff{casting $ to type $|casting between types}0,1}2" + " changes pointer-authentication of pointee type">; def err_typecheck_comparison_of_distinct_blocks : Error< "comparison of distinct block types%diff{ ($ and $)|}0,1">; @@ -8939,6 +8976,9 @@ def err_atomic_op_needs_non_const_atomic : Error< def err_atomic_op_needs_non_const_pointer : Error< "address argument to atomic operation must be a pointer to non-const " "type (%0 invalid)">; +def err_atomic_op_needs_non_address_discriminated_pointer : Error< + "address argument to %select{atomic|__sync}0 operation must be a pointer to a non address discriminated " + "type (%1 invalid)">; def err_atomic_op_needs_trivial_copy : Error< "address argument to atomic operation must be a pointer to a " "trivially-copyable type (%0 invalid)">; @@ -9205,6 +9245,8 @@ def ext_typecheck_cond_pointer_integer_mismatch : ExtWarn< "pointer/integer type mismatch in conditional expression" "%diff{ ($ and $)|}0,1">, InGroup>; +def err_typecheck_cond_incompatible_ptrauth : Error< + "__ptrauth qualification mismatch%diff{ ($ and $)|}0,1">; def err_typecheck_choose_expr_requires_constant : Error< "'__builtin_choose_expr' requires a constant expression">; def warn_unused_expr : Warning<"expression result unused">, diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index dc71ef8f98692..6853a7969e929 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -104,6 +104,7 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics) +FEATURE(ptrauth_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 8c54661e65cf4..68a214452e28b 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -346,6 +346,7 @@ KEYWORD(_Thread_local , KEYALL) KEYWORD(__func__ , KEYALL) KEYWORD(__objc_yes , KEYALL) KEYWORD(__objc_no , KEYALL) +KEYWORD(__ptrauth , KEYALL) // C++ 2.11p1: Keywords. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 35bb1a19d40f0..e3049914289bd 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3151,6 +3151,8 @@ class Parser : public CodeCompletionHandler { SourceLocation *endLoc = nullptr); ExprResult ParseExtIntegerArgument(); + void ParsePtrauthQualifier(ParsedAttributes &Attrs); + VirtSpecifiers::Specifier isCXX11VirtSpecifier(const Token &Tok) const; VirtSpecifiers::Specifier isCXX11VirtSpecifier() const { return isCXX11VirtSpecifier(Tok); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7bfdaaae45a93..211d3941921ff 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3460,6 +3460,17 @@ class Sema final : public SemaBase { bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key); + enum PointerAuthDiscArgKind { + // Address discrimination argument of __ptrauth. + PADAK_AddrDiscPtrAuth, + + // Extra discriminator argument of __ptrauth. + PADAK_ExtraDiscPtrAuth, + }; + + bool checkPointerAuthDiscriminatorArg(Expr *arg, PointerAuthDiscArgKind kind, + unsigned &intVal); + /// Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. void DiagnoseFunctionSpecifiers(const DeclSpec &DS); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a465cdfcf3c89..c1dc730eaa2d5 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11046,6 +11046,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || LQuals.getAddressSpace() != RQuals.getAddressSpace() || LQuals.getObjCLifetime() != RQuals.getObjCLifetime() || + !LQuals.getPointerAuth().isEquivalent(RQuals.getPointerAuth()) || LQuals.hasUnaligned() != RQuals.hasUnaligned()) return {}; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index b573c2713a3aa..c2c550076ea07 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1072,6 +1072,33 @@ void CXXRecordDecl::addedMember(Decl *D) { } else if (!T.isCXX98PODType(Context)) data().PlainOldData = false; + // If a class has an address-discriminated signed pointer member, it is a + // non-POD type and its copy constructor, move constructor, copy assignment + // operator, move assignment operator are non-trivial. + if (PointerAuthQualifier Q = T.getPointerAuth()) { + if (Q.isAddressDiscriminated()) { + struct DefinitionData &Data = data(); + Data.PlainOldData = false; + Data.HasTrivialSpecialMembers &= + ~(SMF_CopyConstructor | SMF_MoveConstructor | SMF_CopyAssignment | + SMF_MoveAssignment); + setArgPassingRestrictions(RecordArgPassingKind::CanNeverPassInRegs); + + // Copy/move constructors/assignment operators of a union are deleted by + // default if it has an address-discriminated ptrauth field. + if (isUnion()) { + data().DefaultedCopyConstructorIsDeleted = true; + data().DefaultedMoveConstructorIsDeleted = true; + data().DefaultedCopyAssignmentIsDeleted = true; + data().DefaultedMoveAssignmentIsDeleted = true; + data().NeedOverloadResolutionForCopyConstructor = true; + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForCopyAssignment = true; + data().NeedOverloadResolutionForMoveAssignment = true; + } + } + } + if (T->isReferenceType()) { if (!Field->hasInClassInitializer()) data().HasUninitializedReferenceMember = true; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index d46d621d4c7d4..1b78eeb29f9da 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2822,6 +2822,26 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp if (Quals.hasUnaligned()) mangleVendorQualifier("__unaligned"); + // __ptrauth. Note that this is parameterized. + if (auto ptrauth = Quals.getPointerAuth()) { + mangleVendorQualifier("__ptrauth"); + // For now, since we only allow non-dependent arguments, we can just + // inline the mangling of those arguments as literals. We treat the + // key and extra-discriminator arguments as 'unsigned int' and the + // address-discriminated argument as 'bool'. + Out << "I" + "Lj" + << ptrauth.getKey() + << "E" + "Lb" + << unsigned(ptrauth.isAddressDiscriminated()) + << "E" + "Lj" + << ptrauth.getExtraDiscriminator() + << "E" + "E"; + } + // Remaining ARC ownership qualifiers. switch (Quals.getObjCLifetime()) { case Qualifiers::OCL_None: diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ffec3ef9d2269..e5fd7b47cb9c2 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1950,6 +1950,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::Ptr64: case attr::SPtr: case attr::UPtr: + case attr::PointerAuth: case attr::AddressSpace: case attr::CmseNSCall: case attr::AnnotateType: @@ -2413,6 +2414,33 @@ void clang::printTemplateArgumentList(raw_ostream &OS, printTo(OS, Args, Policy, TPL, /*isPack*/ false, /*parmIndex*/ 0); } +std::string PointerAuthQualifier::getAsString() const { + LangOptions LO; + return getAsString(PrintingPolicy(LO)); +} + +std::string PointerAuthQualifier::getAsString(const PrintingPolicy &P) const { + SmallString<64> Buf; + llvm::raw_svector_ostream StrOS(Buf); + print(StrOS, P); + return StrOS.str().str(); +} + +bool PointerAuthQualifier::isEmptyWhenPrinted(const PrintingPolicy &P) const { + return !isPresent(); +} + +void PointerAuthQualifier::print(raw_ostream &OS, + const PrintingPolicy &P) const { + if (!isPresent()) + return; + + OS << "__ptrauth("; + OS << getKey(); + OS << "," << unsigned(isAddressDiscriminated()) << "," + << getExtraDiscriminator() << ")"; +} + std::string Qualifiers::getAsString() const { LangOptions LO; return getAsString(PrintingPolicy(LO)); @@ -2442,6 +2470,10 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)) return false; + if (auto pointerAuth = getPointerAuth()) + if (!pointerAuth.isEmptyWhenPrinted(Policy)) + return false; + return true; } @@ -2548,6 +2580,14 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, } } + if (auto pointerAuth = getPointerAuth()) { + if (addSpace) + OS << ' '; + addSpace = true; + + pointerAuth.print(OS, Policy); + } + if (appendSpaceIfNonEmpty && addSpace) OS << ' '; } diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 667e260f2228d..274fb41484934 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -930,6 +930,9 @@ namespace { Qualifiers Qual = F->getType().getQualifiers(); if (Qual.hasVolatile() || Qual.hasObjCLifetime()) return false; + if (PointerAuthQualifier Q = F->getType().getPointerAuth()) + if (Q.isAddressDiscriminated()) + return false; return true; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 3d8a715b692de..ae4026a84601e 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1015,8 +1015,23 @@ llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, // additional ones. llvm::dwarf::Tag Tag = getNextQualifier(Qc); if (!Tag) { - assert(Qc.empty() && "Unknown type qualifier for debug info"); - return getOrCreateType(QualType(T, 0), Unit); + if (Qc.getPointerAuth()) { + unsigned Key = Qc.getPointerAuth().getKey(); + bool IsDiscr = Qc.getPointerAuth().isAddressDiscriminated(); + unsigned ExtraDiscr = Qc.getPointerAuth().getExtraDiscriminator(); + bool IsaPointer = Qc.getPointerAuth().isIsaPointer(); + bool AuthenticatesNullValues = + Qc.getPointerAuth().authenticatesNullValues(); + Qc.removePointerAuth(); + assert(Qc.empty() && "Unknown type qualifier for debug info"); + auto *FromTy = getOrCreateType(QualType(T, 0), Unit); + return DBuilder.createPtrAuthQualifiedType( + FromTy, Key, IsDiscr, ExtraDiscr, /*IsaPointer=*/IsaPointer, + /*AuthenticatesNullValues=*/AuthenticatesNullValues); + } else { + assert(Qc.empty() && "Unknown type qualifier for debug info"); + return getOrCreateType(QualType(T, 0), Unit); + } } auto *FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index c3251bb5ab565..39330853ce705 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -795,7 +795,13 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, LValue lvalue, bool capturedByInit) { Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime(); if (!lifetime) { - llvm::Value *value = EmitScalarExpr(init); + llvm::Value *value; + if (auto ptrauth = lvalue.getQuals().getPointerAuth()) { + value = EmitPointerAuthQualify(ptrauth, init, lvalue.getAddress()); + lvalue.getQuals().removePointerAuth(); + } else { + value = EmitScalarExpr(init); + } if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast(D)); EmitNullabilityCheck(lvalue, value, init->getExprLoc()); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 5f58a64d8386c..43dab7b41b8a1 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2190,6 +2190,15 @@ RValue CodeGenFunction::EmitLoadOfAnyValue(LValue LV, AggValueSlot Slot, /// method emits the address of the lvalue, then loads the result as an rvalue, /// returning the rvalue. RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { + // Load from __ptrauth. + if (auto ptrauth = LV.getQuals().getPointerAuth()) { + LV.getQuals().removePointerAuth(); + auto value = EmitLoadOfLValue(LV, Loc).getScalarVal(); + return RValue::get(EmitPointerAuthUnqualify(ptrauth, value, LV.getType(), + LV.getAddress(), + /*known nonnull*/ false)); + } + if (LV.isObjCWeak()) { // load of a __weak object. Address AddrWeakObj = LV.getAddress(); @@ -2417,6 +2426,13 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, return EmitStoreThroughBitfieldLValue(Src, Dst); } + // Handle __ptrauth qualification by re-signing the value. + if (auto pointerAuth = Dst.getQuals().getPointerAuth()) { + Src = RValue::get(EmitPointerAuthQualify(pointerAuth, Src.getScalarVal(), + Dst.getType(), Dst.getAddress(), + /*known nonnull*/ false)); + } + // There's special magic for assigning into an ARC-qualified l-value. if (Qualifiers::ObjCLifetime Lifetime = Dst.getQuals().getObjCLifetime()) { switch (Lifetime) { @@ -5555,6 +5571,27 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) { return EmitCallee(ICE->getSubExpr()); } + // Try to remember the original __ptrauth qualifier for loads of + // function pointers. + if (ICE->getCastKind() == CK_LValueToRValue) { + auto subExpr = ICE->getSubExpr(); + if (auto ptrType = subExpr->getType()->getAs()) { + auto result = EmitOrigPointerRValue(E); + + QualType functionType = ptrType->getPointeeType(); + assert(functionType->isFunctionType()); + + GlobalDecl GD; + if (const auto *VD = + dyn_cast_or_null(E->getReferencedDeclOfCallee())) { + GD = GlobalDecl(VD); + } + CGCalleeInfo calleeInfo(functionType->getAs(), GD); + CGCallee callee(calleeInfo, result.first, result.second); + return callee; + } + } + // Resolve direct calls. } else if (auto DRE = dyn_cast(E)) { if (auto FD = dyn_cast(DRE->getDecl())) { @@ -5617,6 +5654,17 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { switch (getEvaluationKind(E->getType())) { case TEK_Scalar: { + if (auto ptrauth = E->getLHS()->getType().getPointerAuth()) { + LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); + LValue CopiedLV = LV; + CopiedLV.getQuals().removePointerAuth(); + llvm::Value *RV = + EmitPointerAuthQualify(ptrauth, E->getRHS(), CopiedLV.getAddress()); + EmitNullabilityCheck(CopiedLV, RV, E->getExprLoc()); + EmitStoreThroughLValue(RValue::get(RV), CopiedLV); + return LV; + } + switch (E->getLHS()->getType().getObjCLifetime()) { case Qualifiers::OCL_Strong: return EmitARCStoreStrong(E, /*ignored*/ false).first; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index f22321f0e738a..a66e937c9eabc 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1956,10 +1956,13 @@ namespace { struct ConstantLValue { llvm::Constant *Value; bool HasOffsetApplied; + bool HasDestPointerAuth; /*implicit*/ ConstantLValue(llvm::Constant *value, - bool hasOffsetApplied = false) - : Value(value), HasOffsetApplied(hasOffsetApplied) {} + bool hasOffsetApplied = false, + bool hasDestPointerAuth = false) + : Value(value), HasOffsetApplied(hasOffsetApplied), + HasDestPointerAuth(hasDestPointerAuth) {} /*implicit*/ ConstantLValue(ConstantAddress address) : ConstantLValue(address.getPointer()) {} @@ -2064,6 +2067,15 @@ llvm::Constant *ConstantLValueEmitter::tryEmit() { value = applyOffset(value); } + // Apply pointer-auth signing from the destination type. + if (auto pointerAuth = DestType.getPointerAuth()) { + if (!result.HasDestPointerAuth) { + value = Emitter.tryEmitConstantSignedPointer(value, pointerAuth); + if (!value) + return nullptr; + } + } + // Convert to the appropriate type; this could be an lvalue for // an integer. FIXME: performAddrSpaceCast if (isa(destTy)) @@ -2107,6 +2119,12 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { return CGM.GetWeakRefReference(D).getPointer(); auto PtrAuthSign = [&](llvm::Constant *C) { + if (auto pointerAuth = DestType.getPointerAuth()) { + C = applyOffset(C); + C = Emitter.tryEmitConstantSignedPointer(C, pointerAuth); + return ConstantLValue(C, /*applied offset*/ true, /*signed*/ true); + } + CGPointerAuthInfo AuthInfo; if (EnablePtrAuthFunctionTypeDiscrimination) @@ -2120,7 +2138,7 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { C = CGM.getConstantSignedPointer( C, AuthInfo.getKey(), nullptr, cast_or_null(AuthInfo.getDiscriminator())); - return ConstantLValue(C, /*applied offset*/ true); + return ConstantLValue(C, /*applied offset*/ true, /*signed*/ true); } return ConstantLValue(C); @@ -2334,6 +2352,9 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, QualType DestType, EnablePtrAuthFunctionTypeDiscrimination) .tryEmit(); case APValue::Int: + if (DestType.getPointerAuth() && 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 a17d68424bbce..05c76cf85581c 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2196,6 +2196,58 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { return V; } +static bool isDeclRefKnownNonNull(CodeGenFunction &CGF, const ValueDecl *D) { + return !D->isWeak(); +} + +static bool isLValueKnownNonNull(CodeGenFunction &CGF, const Expr *E) { + E = E->IgnoreParens(); + + if (auto UO = dyn_cast(E)) { + if (UO->getOpcode() == UO_Deref) { + return CGF.isPointerKnownNonNull(UO->getSubExpr()); + } + } + + if (auto DRE = dyn_cast(E)) { + return isDeclRefKnownNonNull(CGF, DRE->getDecl()); + } else if (auto ME = dyn_cast(E)) { + if (isa(ME->getMemberDecl())) + return true; + return isDeclRefKnownNonNull(CGF, ME->getMemberDecl()); + } + + // Array subscripts? Anything else? + + return false; +} + +bool CodeGenFunction::isPointerKnownNonNull(const Expr *E) { + assert(E->getType()->isSignableType()); + + E = E->IgnoreParens(); + + if (isa(E)) + return true; + + if (auto UO = dyn_cast(E)) { + if (UO->getOpcode() == UO_AddrOf) { + return isLValueKnownNonNull(*this, UO->getSubExpr()); + } + } + + if (auto CE = dyn_cast(E)) { + if (CE->getCastKind() == CK_FunctionToPointerDecay || + CE->getCastKind() == CK_ArrayToPointerDecay) { + return isLValueKnownNonNull(*this, CE->getSubExpr()); + } + } + + // Maybe honor __nonnull? + + return false; +} + bool CodeGenFunction::ShouldNullCheckClassCastValue(const CastExpr *CE) { const Expr *E = CE->getSubExpr(); @@ -4798,6 +4850,21 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { Value *RHS; LValue LHS; + if (auto ptrauth = E->getLHS()->getType().getPointerAuth()) { + LValue LV = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); + LV.getQuals().removePointerAuth(); + llvm::Value *RV = + CGF.EmitPointerAuthQualify(ptrauth, E->getRHS(), LV.getAddress()); + CGF.EmitNullabilityCheck(LV, RV, E->getExprLoc()); + CGF.EmitStoreThroughLValue(RValue::get(RV), LV); + + if (Ignore) + return nullptr; + RV = CGF.EmitPointerAuthUnqualify(ptrauth, RV, LV.getType(), + LV.getAddress(), /*nonnull*/ false); + return RV; + } + switch (E->getLHS()->getType().getObjCLifetime()) { case Qualifiers::OCL_Strong: std::tie(LHS, RHS) = CGF.EmitARCStoreStrong(E, Ignore); diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 0c63b9d6bb7e7..5cd9cba6b41d1 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -125,6 +125,33 @@ CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo( Schema.authenticatesNullValues(), Discriminator); } +CGPointerAuthInfo +CodeGenFunction::EmitPointerAuthInfo(PointerAuthQualifier Qual, + Address StorageAddress) { + assert(Qual && "don't call this if you don't know that the Qual is present"); + if (Qual.hasKeyNone()) + return CGPointerAuthInfo(); + + llvm::Value *Discriminator = nullptr; + if (unsigned Extra = Qual.getExtraDiscriminator()) + Discriminator = llvm::ConstantInt::get(IntPtrTy, Extra); + + if (Qual.isAddressDiscriminated()) { + assert(StorageAddress.isValid() && + "address discrimination without address"); + llvm::Value *StoragePtr = StorageAddress.emitRawPointer(*this); + if (Discriminator) + Discriminator = + EmitPointerAuthBlendDiscriminator(StoragePtr, Discriminator); + else + Discriminator = Builder.CreatePtrToInt(StoragePtr, IntPtrTy); + } + + return CGPointerAuthInfo(Qual.getKey(), Qual.getAuthenticationMode(), + Qual.isIsaPointer(), Qual.authenticatesNullValues(), + Discriminator); +} + /// Return the natural pointer authentication for values of the given /// pointee type. static CGPointerAuthInfo @@ -166,6 +193,102 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) { return ::getPointerAuthInfoForType(*this, T); } +static std::pair +emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &lv, + SourceLocation loc) { + auto value = CGF.EmitLoadOfScalar(lv, loc); + CGPointerAuthInfo authInfo; + if (auto ptrauth = lv.getQuals().getPointerAuth()) { + authInfo = CGF.EmitPointerAuthInfo(ptrauth, lv.getAddress()); + } else { + authInfo = getPointerAuthInfoForType(CGF.CGM, lv.getType()); + } + return {value, authInfo}; +} + +std::pair +CodeGenFunction::EmitOrigPointerRValue(const Expr *E) { + assert(E->getType()->isSignableType()); + + E = E->IgnoreParens(); + if (auto load = dyn_cast(E)) { + if (load->getCastKind() == CK_LValueToRValue) { + E = load->getSubExpr()->IgnoreParens(); + + // We're semantically required to not emit loads of certain DREs naively. + if (auto refExpr = dyn_cast(const_cast(E))) { + if (auto result = tryEmitAsConstant(refExpr)) { + // Fold away a use of an intermediate variable. + if (!result.isReference()) + return {result.getValue(), + getPointerAuthInfoForType(CGM, refExpr->getType())}; + + // Fold away a use of an intermediate reference. + auto lv = result.getReferenceLValue(*this, refExpr); + return emitLoadOfOrigPointerRValue(*this, lv, refExpr->getLocation()); + } + } + + // Otherwise, load and use the pointer + auto lv = EmitCheckedLValue(E, CodeGenFunction::TCK_Load); + return emitLoadOfOrigPointerRValue(*this, lv, E->getExprLoc()); + } + } + + // Emit direct references to functions without authentication. + if (auto DRE = dyn_cast(E)) { + if (auto FD = dyn_cast(DRE->getDecl())) { + return {CGM.getRawFunctionPointer(FD), CGPointerAuthInfo()}; + } + } else if (auto ME = dyn_cast(E)) { + if (auto FD = dyn_cast(ME->getMemberDecl())) { + EmitIgnoredExpr(ME->getBase()); + return {CGM.getRawFunctionPointer(FD), CGPointerAuthInfo()}; + } + } + + // Fallback: just use the normal rules for the type. + auto value = EmitScalarExpr(E); + return {value, getPointerAuthInfoForType(CGM, E->getType())}; +} + +llvm::Value * +CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier destQualifier, + const Expr *E, + Address destStorageAddress) { + assert(destQualifier); + + auto src = EmitOrigPointerRValue(E); + auto value = src.first; + auto curAuthInfo = src.second; + + auto destAuthInfo = EmitPointerAuthInfo(destQualifier, destStorageAddress); + return emitPointerAuthResign(value, E->getType(), curAuthInfo, destAuthInfo, + isPointerKnownNonNull(E)); +} + +llvm::Value *CodeGenFunction::EmitPointerAuthQualify( + PointerAuthQualifier destQualifier, llvm::Value *value, + QualType pointerType, Address destStorageAddress, bool isKnownNonNull) { + assert(destQualifier); + + auto curAuthInfo = getPointerAuthInfoForType(CGM, pointerType); + auto destAuthInfo = EmitPointerAuthInfo(destQualifier, destStorageAddress); + return emitPointerAuthResign(value, pointerType, curAuthInfo, destAuthInfo, + isKnownNonNull); +} + +llvm::Value *CodeGenFunction::EmitPointerAuthUnqualify( + PointerAuthQualifier curQualifier, llvm::Value *value, QualType pointerType, + Address curStorageAddress, bool isKnownNonNull) { + assert(curQualifier); + + auto curAuthInfo = EmitPointerAuthInfo(curQualifier, curStorageAddress); + auto destAuthInfo = getPointerAuthInfoForType(CGM, pointerType); + return emitPointerAuthResign(value, pointerType, curAuthInfo, destAuthInfo, + isKnownNonNull); +} + static bool isZeroConstant(const llvm::Value *Value) { if (const auto *CI = dyn_cast(Value)) return CI->isZero(); @@ -288,6 +411,23 @@ llvm::Value *CodeGenFunction::emitPointerAuthResign( return Value; } +void CodeGenFunction::EmitPointerAuthCopy(PointerAuthQualifier Qual, QualType T, + Address DestAddress, + Address SrcAddress) { + assert(Qual); + llvm::Value *Value = Builder.CreateLoad(SrcAddress); + + // If we're using address-discrimination, we have to re-sign the value. + if (Qual.isAddressDiscriminated()) { + CGPointerAuthInfo SrcPtrAuth = EmitPointerAuthInfo(Qual, SrcAddress); + CGPointerAuthInfo DestPtrAuth = EmitPointerAuthInfo(Qual, DestAddress); + Value = emitPointerAuthResign(Value, T, SrcPtrAuth, DestPtrAuth, + /*IsKnownNonNull=*/false); + } + + Builder.CreateStore(Value, DestAddress); +} + llvm::Constant * CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, llvm::Constant *StorageAddress, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 67e3019565cd0..e7729207cc6a6 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4457,6 +4457,26 @@ class CodeGenFunction : public CodeGenTypeCache { const CGPointerAuthInfo &Info, SmallVectorImpl &Bundles); + CGPointerAuthInfo EmitPointerAuthInfo(PointerAuthQualifier qualifier, + Address storageAddress); + llvm::Value *EmitPointerAuthQualify(PointerAuthQualifier qualifier, + llvm::Value *pointer, QualType valueType, + Address storageAddress, + bool isKnownNonNull); + llvm::Value *EmitPointerAuthQualify(PointerAuthQualifier qualifier, + const Expr *pointerExpr, + Address storageAddress); + llvm::Value *EmitPointerAuthUnqualify(PointerAuthQualifier qualifier, + llvm::Value *pointer, + QualType pointerType, + Address storageAddress, + bool isKnownNonNull); + void EmitPointerAuthCopy(PointerAuthQualifier qualifier, QualType type, + Address destField, Address srcField); + + std::pair + EmitOrigPointerRValue(const Expr *E); + llvm::Value *authPointerToPointerCast(llvm::Value *ResultPtr, QualType SourceType, QualType DestType); Address authPointerToPointerCast(Address Ptr, QualType SourceType, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7ce9a9cea1c7a..2a14a6a34eede 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3366,6 +3366,40 @@ void Parser::DistributeCLateParsedAttrs(Decl *Dcl, } } +/// type-qualifier: +/// ('__ptrauth') '(' constant-expression +/// (',' constant-expression)[opt] +/// (',' constant-expression)[opt] ')' +void Parser::ParsePtrauthQualifier(ParsedAttributes &attrs) { + assert(Tok.is(tok::kw___ptrauth)); + + IdentifierInfo *kwName = Tok.getIdentifierInfo(); + SourceLocation kwLoc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume()) + return; + + ArgsVector argExprs; + do { + ExprResult expr = ParseAssignmentExpression(); + if (expr.isInvalid()) { + T.skipToEnd(); + return; + } + argExprs.push_back(expr.get()); + } while (TryConsumeToken(tok::comma)); + + T.consumeClose(); + SourceLocation endLoc = T.getCloseLocation(); + + attrs.addNew(kwName, SourceRange(kwLoc, endLoc), + /*scope*/ nullptr, SourceLocation(), argExprs.data(), + argExprs.size(), + ParsedAttr::Form::Keyword(/*IsAlignAs=*/false, + /*IsRegularKeywordAttribute=*/false)); +} + /// Bounds attributes (e.g., counted_by): /// AttrName '(' expression ')' void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, @@ -4227,6 +4261,11 @@ void Parser::ParseDeclarationSpecifiers( getLangOpts()); break; + // __ptrauth qualifier. + case tok::kw___ptrauth: + ParsePtrauthQualifier(DS.getAttributes()); + continue; + case tok::kw___sptr: case tok::kw___uptr: case tok::kw___ptr64: @@ -5924,6 +5963,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___ptr32: case tok::kw___pascal: case tok::kw___unaligned: + case tok::kw___ptrauth: case tok::kw__Nonnull: case tok::kw__Nullable: @@ -6213,6 +6253,7 @@ bool Parser::isDeclarationSpecifier( case tok::kw___forceinline: case tok::kw___pascal: case tok::kw___unaligned: + case tok::kw___ptrauth: case tok::kw__Nonnull: case tok::kw__Nullable: @@ -6475,6 +6516,12 @@ void Parser::ParseTypeQualifierListOpt( ParseHLSLQualifiers(DS.getAttributes()); continue; + // __ptrauth qualifier. + case tok::kw___ptrauth: + ParsePtrauthQualifier(DS.getAttributes()); + EndLoc = PrevTokLocation; + continue; + case tok::kw___unaligned: isInvalid = DS.SetTypeQual(DeclSpec::TQ_unaligned, Loc, PrevSpec, DiagID, getLangOpts()); diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index eca8363ee9605..d4372c3470784 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -73,7 +73,7 @@ namespace { // value of the expression to the unqualified, non-atomic version of // the named type. if (!S.Context.getLangOpts().ObjC && !DestType->isRecordType() && - !DestType->isArrayType()) { + !DestType->isArrayType() && !DestType.getPointerAuth()) { DestType = DestType.getAtomicUnqualifiedType(); } @@ -167,6 +167,14 @@ namespace { SrcExpr = src; } + void checkQualifiedDestType() { + // Destination type may not be qualified with __ptrauth. + if (DestType.getPointerAuth()) { + Self.Diag(DestRange.getBegin(), diag::err_ptrauth_qualifier_cast) + << DestType << DestRange; + } + } + /// Check for and handle non-overload placeholder expressions. void checkNonOverloadPlaceholders() { if (!isPlaceholder() || isPlaceholder(BuiltinType::Overload)) @@ -308,6 +316,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, Op.OpRange = SourceRange(OpLoc, Parens.getEnd()); Op.DestRange = AngleBrackets; + Op.checkQualifiedDestType(); + switch (Kind) { default: llvm_unreachable("Unknown C++ cast!"); @@ -3359,6 +3369,8 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, // -Wcast-qual DiagnoseCastQual(Op.Self, Op.SrcExpr, Op.DestType); + Op.checkQualifiedDestType(); + return Op.complete(CStyleCastExpr::Create( Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(), &Op.BasePath, CurFPFeatureOverrides(), CastTypeInfo, LPLoc, RPLoc)); @@ -3378,6 +3390,8 @@ ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo, if (Op.SrcExpr.isInvalid()) return ExprError(); + Op.checkQualifiedDestType(); + auto *SubExpr = Op.SrcExpr.get(); if (auto *BindExpr = dyn_cast(SubExpr)) SubExpr = BindExpr->getSubExpr(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index bde92e04b6b83..4aefc12789c13 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1540,6 +1540,54 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) { return false; } +bool Sema::checkPointerAuthDiscriminatorArg(Expr *arg, + PointerAuthDiscArgKind kind, + unsigned &intVal) { + if (!arg) { + intVal = 0; + return true; + } + + std::optional result = arg->getIntegerConstantExpr(Context); + if (!result) { + Diag(arg->getExprLoc(), diag::err_ptrauth_arg_not_ice); + return false; + } + + unsigned max; + bool isAddrDiscArg = false; + + switch (kind) { + case PADAK_AddrDiscPtrAuth: + max = 1; + isAddrDiscArg = true; + break; + case PADAK_ExtraDiscPtrAuth: + max = PointerAuthQualifier::MaxDiscriminator; + break; + }; + + if (*result < 0 || *result > max) { + llvm::SmallString<32> value; + { + llvm::raw_svector_ostream str(value); + str << *result; + } + + if (isAddrDiscArg) + Diag(arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid) + << value; + else + Diag(arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid) + << value << max; + + return false; + }; + + intVal = result->getZExtValue(); + return true; +} + static std::pair findConstantBaseAndOffset(Sema &S, Expr *E) { // Must evaluate as a pointer. @@ -3795,6 +3843,14 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, return ExprError(); } + auto PointerAuth = AtomTy.getPointerAuth(); + if (PointerAuth && PointerAuth.isAddressDiscriminated()) { + Diag(ExprRange.getBegin(), + diag::err_atomic_op_needs_non_address_discriminated_pointer) + << 0 << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } + // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // GCC does not enforce these rules for GNU atomics, but we do to help catch @@ -4161,6 +4217,13 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { << FirstArg->getType() << 0 << FirstArg->getSourceRange(); return ExprError(); } + auto pointerAuth = ValType.getPointerAuth(); + if (pointerAuth && pointerAuth.isAddressDiscriminated()) { + Diag(FirstArg->getBeginLoc(), + diag::err_atomic_op_needs_non_address_discriminated_pointer) + << 1 << ValType << FirstArg->getSourceRange(); + return ExprError(); + } if (ValType.isConstQualified()) { Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_cannot_be_const) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 575bd292f27de..cbd574654a0ff 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15099,6 +15099,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, New->setType(T); } + // __ptrauth is forbidden on parameters. + if (T.getPointerAuth()) { + Diag(NameLoc, diag::err_ptrauth_qualifier_invalid) + << T << (int)!T->isSignableType() << 1; + New->setInvalidDecl(); + } + // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have @@ -19033,9 +19040,14 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, RecordArgPassingKind::CanNeverPassInRegs) Record->setArgPassingRestrictions( RecordArgPassingKind::CanNeverPassInRegs); - } else if (FT.getQualifiers().getObjCLifetime() == Qualifiers::OCL_Weak) + } else if (FT.getQualifiers().getObjCLifetime() == Qualifiers::OCL_Weak) { Record->setArgPassingRestrictions( RecordArgPassingKind::CanNeverPassInRegs); + } else if (PointerAuthQualifier Q = FT.getPointerAuth()) { + if (Q.isAddressDiscriminated()) + Record->setArgPassingRestrictions( + RecordArgPassingKind::CanNeverPassInRegs); + } } if (Record && FD->getType().isVolatileQualified()) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1cca8ac9b9343..1b820c7c88522 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9250,6 +9250,8 @@ struct SpecialMemberDeletionInfo bool shouldDeleteForVariantObjCPtrMember(FieldDecl *FD, QualType FieldType); + bool shouldDeleteForVariantPtrAuthMember(FieldDecl *FD, QualType FieldType); + bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); } bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); } @@ -9418,6 +9420,29 @@ bool SpecialMemberDeletionInfo::shouldDeleteForVariantObjCPtrMember( return true; } +bool SpecialMemberDeletionInfo::shouldDeleteForVariantPtrAuthMember( + FieldDecl *FD, QualType FieldType) { + // Copy/move constructors/assignment operators are deleted if the field has an + // address-discriminated ptrauth qualifier. + PointerAuthQualifier Q = FieldType.getPointerAuth(); + + if (!Q || !Q.isAddressDiscriminated()) + return false; + + if (CSM == CXXSpecialMemberKind::DefaultConstructor || + CSM == CXXSpecialMemberKind::Destructor) + return false; + + if (Diagnose) { + auto *ParentClass = cast(FD->getParent()); + S.Diag(FD->getLocation(), diag::note_deleted_special_member_class_subobject) + << llvm::to_underlying(getEffectiveCSM()) << ParentClass + << /*IsField*/ true << FD << 4 << /*IsDtorCallInCtor*/ false << 2; + } + + return true; +} + /// Check whether we should delete a special member function due to the class /// having a particular direct or virtual base class. bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { @@ -9456,6 +9481,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (inUnion() && shouldDeleteForVariantObjCPtrMember(FD, FieldType)) return true; + if (inUnion() && shouldDeleteForVariantPtrAuthMember(FD, FieldType)) + return true; + if (CSM == CXXSpecialMemberKind::DefaultConstructor) { // For a default constructor, all references must be initialized in-class // and, if a union, it must have a non-const member. @@ -9519,6 +9547,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (shouldDeleteForVariantObjCPtrMember(&*UI, UnionFieldType)) return true; + if (shouldDeleteForVariantPtrAuthMember(&*UI, UnionFieldType)) + return true; + if (!UnionFieldType.isConstQualified()) AllVariantFieldsAreConst = false; @@ -10363,6 +10394,12 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { return; } + // Ill-formed if the field is an address-discriminated pointer. + if (FT.hasAddressDiscriminatedPointerAuth()) { + PrintDiagAndRemoveAttr(6); + return; + } + if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs()) if (!RT->isDependentType() && !cast(RT->getDecl())->canPassInRegisters()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 74c0e01705905..d854cbdd8eb11 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7957,6 +7957,13 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, lhQual.removeCVRQualifiers(); rhQual.removeCVRQualifiers(); + if (!lhQual.getPointerAuth().isEquivalent(rhQual.getPointerAuth())) { + S.Diag(Loc, diag::err_typecheck_cond_incompatible_ptrauth) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + // OpenCL v2.0 specification doesn't extend compatibility of type qualifiers // (C99 6.7.3) for address spaces. We assume that the check should behave in // the same manner as it's defined for CVR qualifiers, so for OpenCL two @@ -8873,6 +8880,10 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType, else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; + // Treat pointer-auth mismatches as fatal. + else if (!lhq.getPointerAuth().isEquivalent(rhq.getPointerAuth())) + ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; + // For GCC/MS compatibility, other qualifier mismatches are treated // as still compatible in C. else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; @@ -16689,6 +16700,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) { DiagKind = diag::err_typecheck_incompatible_ownership; break; + } else if (!lhq.getPointerAuth().isEquivalent(rhq.getPointerAuth())) { + DiagKind = diag::err_typecheck_incompatible_ptrauth; + break; } llvm_unreachable("unknown error case for discarding qualifiers!"); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 51c4a36808fce..763653e81c5b4 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -7266,6 +7266,11 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, else return QualType(); + if (Q1.getPointerAuth().isEquivalent(Q2.getPointerAuth())) + Quals.setPointerAuth(Q1.getPointerAuth()); + else + return QualType(); + Steps.back().Quals = Quals; if (Q1 != Quals || Q2 != Quals) NeedConstBefore = Steps.size() - 1; diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 031f2a6af8774..246f19840a795 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -182,6 +182,10 @@ 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 << (int)!T->isSignableType() << 2; + } if (!getOwnershipRule(Attributes)) { Attributes |= deducePropertyOwnershipFromType(SemaRef, T); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 86074a4f3a585..521d14ba1f84b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11222,6 +11222,17 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, return; } + if (!FromQs.getPointerAuth().isEquivalent(ToQs.getPointerAuth())) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ptrauth) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << FromTy << !!FromQs.getPointerAuth() + << FromQs.getPointerAuth().getAsString() << !!ToQs.getPointerAuth() + << ToQs.getPointerAuth().getAsString() << I + 1 + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); + return; + } + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); assert(CVR && "expected qualifiers mismatch"); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 6fa39cdccef2b..c4da0f237c833 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2522,6 +2522,13 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { return true; } + // __ptrauth is illegal on a function return type. + if (T.getPointerAuth()) { + Diag(Loc, diag::err_ptrauth_qualifier_invalid) + << T << (int)!T->isSignableType() << 0; + return true; + } + if (T.hasNonTrivialToPrimitiveDestructCUnion() || T.hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn, @@ -2625,6 +2632,11 @@ QualType Sema::BuildFunctionType(QualType T, } else if (ParamType->isWebAssemblyTableType()) { 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 << (int)!T->isSignableType() << 1; + Invalid = true; } // C++2a [dcl.fct]p4: @@ -4923,6 +4935,12 @@ 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 << (int)!T->isSignableType() << 0; + } + if (LangOpts.OpenCL) { // OpenCL v2.0 s6.12.5 - A block cannot be the return value of a // function. @@ -8210,6 +8228,70 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, CurType = S.Context.getVectorType(CurType, numElts, VecKind); } +/// Handle the __ptrauth qualifier. +static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &type, + const ParsedAttr &attr, Sema &S) { + auto attributeName = attr.getAttrName()->getName(); + if (attr.getNumArgs() < 1 || attr.getNumArgs() > 3) { + S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_bad_arg_count) + << attributeName; + attr.setInvalid(); + return; + } + + Expr *keyArg = attr.getArgAsExpr(0); + Expr *isAddressDiscriminatedArg = + attr.getNumArgs() >= 2 ? attr.getArgAsExpr(1) : nullptr; + Expr *extraDiscriminatorArg = + attr.getNumArgs() >= 3 ? attr.getArgAsExpr(2) : nullptr; + + unsigned key; + if (S.checkConstantPointerAuthKey(keyArg, key)) { + attr.setInvalid(); + return; + } + assert(key <= PointerAuthQualifier::MaxKey && "ptrauth key is out of range"); + + bool isInvalid = false; + unsigned isAddressDiscriminated, extraDiscriminator; + isInvalid |= !S.checkPointerAuthDiscriminatorArg(isAddressDiscriminatedArg, + Sema::PADAK_AddrDiscPtrAuth, + isAddressDiscriminated); + isInvalid |= !S.checkPointerAuthDiscriminatorArg( + extraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, extraDiscriminator); + + if (isInvalid) { + attr.setInvalid(); + return; + } + + if (!type->isSignableType() && !type->isDependentType()) { + S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << type; + attr.setInvalid(); + return; + } + + if (type.getPointerAuth()) { + S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_redundant) + << type << attr.getAttrName()->getName(); + attr.setInvalid(); + return; + } + + if (!S.getLangOpts().PointerAuthIntrinsics) { + S.Diag(attr.getLoc(), diag::err_ptrauth_disabled) << attr.getRange(); + attr.setInvalid(); + return; + } + + assert((!isAddressDiscriminatedArg || isAddressDiscriminated <= 1) && + "address discriminator arg should be either 0 or 1"); + PointerAuthQualifier qual = PointerAuthQualifier::Create( + key, isAddressDiscriminated, extraDiscriminator, + PointerAuthenticationMode::SignAndAuth, false, false); + type = S.Context.getPointerAuthType(type, qual); +} + /// HandleArmSveVectorBitsTypeAttr - The "arm_sve_vector_bits" attribute is /// used to create fixed-length versions of sizeless SVE types defined by /// the ACLE, such as svint32_t and svbool_t. @@ -8634,6 +8716,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, HandleOpenCLAccessAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; + case ParsedAttr::AT_PointerAuth: + HandlePtrAuthQualifier(state.getSema().Context, type, attr, + state.getSema()); + attr.setUsedAsTypeAttr(); + break; case ParsedAttr::AT_LifetimeBound: if (TAL == TAL_DeclChunk) HandleLifetimeBoundAttr(state, type, attr); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 4d68ebf0cc452..35bc8d50dc901 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5097,6 +5097,17 @@ QualType TreeTransform::RebuildQualifiedType(QualType T, return QualType(); } + auto LocalPointerAuth = Quals.getPointerAuth(); + 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; + return QualType(); + } + } // C++ [dcl.fct]p7: // [When] adding cv-qualifications on top of the function type [...] the // cv-qualifiers are ignored. diff --git a/clang/test/CodeGen/ptrauth-debuginfo.c b/clang/test/CodeGen/ptrauth-debuginfo.c new file mode 100644 index 0000000000000..214ecafca303c --- /dev/null +++ b/clang/test/CodeGen/ptrauth-debuginfo.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios \ +// RUN: -fptrauth-calls -fptrauth-intrinsics -emit-llvm -fblocks \ +// RUN: %s -debug-info-kind=limited -o - | FileCheck %s + +// Constant initializers for data pointers. +extern int external_int; + +int *__ptrauth(1, 0, 1234) g1 = &external_int; +// CHECK: !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type, +// CHECK-SAME: ptrAuthKey: 1, +// CHECK-SAME: ptrAuthIsAddressDiscriminated: false, +// CHECK-SAME: ptrAuthExtraDiscriminator: 1234, +// CHECK-SAME: ptrAuthIsaPointer: false, +// CHECK-SAME: ptrAuthAuthenticatesNullValues: false) + +struct A { + int value; +}; +struct A *createA(void); + +void f() { + __block struct A *__ptrauth(1, 1, 1236) ptr = createA(); + ^{ + (void)ptr->value; + }(); +} +// CHECK: !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type, +// CHECK-SAME: ptrAuthKey: 1, +// CHECK-SAME: ptrAuthIsAddressDiscriminated: true, +// CHECK-SAME: ptrAuthExtraDiscriminator: 1236, +// CHECK-SAME: ptrAuthIsaPointer: false, +// CHECK-SAME: ptrAuthAuthenticatesNullValues: false) diff --git a/clang/test/CodeGen/ptrauth-qualifier-function.c b/clang/test/CodeGen/ptrauth-qualifier-function.c new file mode 100644 index 0000000000000..f6cde0cd96e62 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-qualifier-function.c @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s +// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s + +#ifdef __cplusplus +extern "C" { +#endif + +void (*fptr)(void); +void (* __ptrauth(0, 0, 42) f2ptr_42_discm)(int); + +// CHECK-LABEL: define void @test_assign_to_qualified +void test_assign_to_qualified() { + f2ptr_42_discm = (void (*)(int))fptr; + + // CHECK: [[ENTRY:.*]]:{{$}} + // CHECK: [[FPTR:%.*]] = load ptr, ptr @fptr + // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR]], null + // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN1:.*]], label %[[JOIN1:.*]] + + // CHECK: [[RESIGN1]]: + // CHECK-NEXT: [[FPTR2:%.*]] = ptrtoint ptr [[FPTR]] to i64 + // CHECK-NEXT: [[FPTR4:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR2]], i32 0, i64 18983, i32 0, i64 2712) + // CHECK-NEXT: [[FPTR5:%.*]] = inttoptr i64 [[FPTR4]] to ptr + // CHECK-NEXT: br label %[[JOIN1]] + + // CHECK: [[JOIN1]]: + // CHECK-NEXT: [[FPTR6:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR5]], %[[RESIGN1]] ] + // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR6]], null + // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] + + // CHECK: [[RESIGN2]]: + // CHECK-NEXT: [[FPTR7:%.*]] = ptrtoint ptr [[FPTR6]] to i64 + // CHECK-NEXT: [[FPTR8:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR7]], i32 0, i64 2712, i32 0, i64 42) + // CHECK-NEXT: [[FPTR9:%.*]] = inttoptr i64 [[FPTR8]] to ptr + // CHECK-NEXT: br label %[[JOIN2]] + + // CHECK: [[JOIN2]] + // CHECK-NEXT: [[FPTR10:%.*]] = phi ptr [ null, %[[JOIN1]] ], [ [[FPTR9]], %[[RESIGN2]] ] + // CHECK-NEXT store void (i32)* [[FPTR10]], void (i32)** @f2ptr_42_discm +} + +// CHECK-LABEL: define void @test_assign_from_qualified +void test_assign_from_qualified() { + fptr = (void (*)(void))f2ptr_42_discm; + + // CHECK: [[ENTRY:.*]]:{{$}} + // CHECK: [[FPTR:%.*]] = load ptr, ptr @f2ptr_42_discm + // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR]], null + // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN1:.*]], label %[[JOIN1:.*]] + + // CHECK: [[RESIGN1]]: + // CHECK-NEXT: [[FPTR1:%.*]] = ptrtoint ptr [[FPTR]] to i64 + // CHECK-NEXT: [[FPTR2:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR1]], i32 0, i64 42, i32 0, i64 2712) + // CHECK-NEXT: [[FPTR3:%.*]] = inttoptr i64 [[FPTR2]] to ptr + // CHECK-NEXT: br label %[[JOIN1]] + + // CHECK: [[JOIN1]]: + // CHECK-NEXT: [[FPTR4:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR3]], %[[RESIGN1]] ] + // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR4]], null + // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] + + // CHECK: [[RESIGN2]]: + // CHECK-NEXT: [[FPTR6:%.*]] = ptrtoint ptr [[FPTR4]] to i64 + // CHECK-NEXT: [[FPTR7:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR6]], i32 0, i64 2712, i32 0, i64 18983) + // CHECK-NEXT: [[FPTR8:%.*]] = inttoptr i64 [[FPTR7]] to ptr + // CHECK-NEXT: br label %[[JOIN2]] + + // CHECK: [[JOIN2]] + // CHECK-NEXT: [[FPTR9:%.*]] = phi ptr [ null, %[[JOIN1]] ], [ [[FPTR8]], %[[RESIGN2]] ] + // CHECK-NEXT store void ()* [[FPTR10]], void ()** @f2ptr_42_discm +} + +#ifdef __cplusplus +} +#endif diff --git a/clang/test/CodeGen/ptrauth-qualifier-loadstore.c b/clang/test/CodeGen/ptrauth-qualifier-loadstore.c new file mode 100644 index 0000000000000..41a87fba58e17 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-qualifier-loadstore.c @@ -0,0 +1,744 @@ +// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s + +#define IQ __ptrauth(1,0,50) +#define AQ __ptrauth(1,1,50) +#define DIFF_IQ __ptrauth(1,0,100) +#define DIFF_AQ __ptrauth(1,1,100) +#define ZERO_IQ __ptrauth(1,0,0) +#define ZERO_AQ __ptrauth(1,1,0) + +extern int external_int; +extern int * global_upi; +extern int * IQ global_iqpi; +extern int * AQ global_aqpi; +extern void use_upi(int *ptr); + +typedef void func_t(void); +extern void external_func(void); +extern func_t *global_upf; +extern func_t * IQ global_iqpf; +extern func_t * AQ global_aqpf; +extern void use_upf(func_t *ptr); + +// Data with address-independent qualifiers. + +// CHECK-LABEL: define void @test_store_data_i_constant() +void test_store_data_i_constant() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @external_int to i64), i32 1, i64 50) +// CHECK-NEXT: [[T0:%.*]] = inttoptr i64 [[SIGN]] to ptr +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * IQ iqpi = &external_int; +// CHECK-NEXT: [[T0:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @external_int to i64), i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T0]] to ptr +// CHECK-NEXT: store ptr [[SIGNED]], ptr [[V]], +// CHECK-NEXT: ret void + iqpi = &external_int; +} + +// CHECK-LABEL: define void @test_store_data_iu() +void test_store_data_iu() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[T0]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * IQ iqpi = global_upi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[T0]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + iqpi = global_upi; +} + +// CHECK-LABEL: define void @test_store_data_ia() +void test_store_data_ia() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * IQ iqpi = global_aqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + iqpi = global_aqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[RESULT:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[RESULT]], ptr [[V]], +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[RESULT]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[RESULT]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 1, i64 50) +// CHECK-NEXT: [[AUTHED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[RESULT:%.*]] = phi ptr [ null, {{.*}} ], [ [[AUTHED]], {{.*}} ] +// CHECK-NEXT: call void @use_upi(ptr noundef [[RESULT]]) + use_upi(iqpi = global_aqpi); +} + +// CHECK-LABEL: define void @test_store_data_ii_same() +void test_store_data_ii_same() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: store ptr [[LOAD]], ptr [[V]], + int * IQ iqpi = global_iqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: store ptr [[LOAD]], ptr [[V]], + iqpi = global_iqpi; +} + +// CHECK-LABEL: define void @test_store_data_ii_different() +void test_store_data_ii_different() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 100) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * DIFF_IQ iqpi = global_iqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 100) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + iqpi = global_iqpi; +} + +// CHECK-LABEL: define void @test_store_data_ii_zero() +void test_store_data_ii_zero() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 0) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * ZERO_IQ iqpi = global_iqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[V]] +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 0, i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr @global_iqpi, + global_iqpi = iqpi; +} + +// CHECK-LABEL: define void @test_load_data_i() +void test_load_data_i() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 1, i64 50) +// CHECK-NEXT: [[AUTHED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[AUTHED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int *upi = global_iqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 1, i64 50) +// CHECK-NEXT: [[AUTHED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[AUTHED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + upi = global_iqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 1, i64 50) +// CHECK-NEXT: [[AUTHED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[AUTHED]], {{.*}} ] +// CHECK-NEXT: call void @use_upi(ptr noundef [[T0]]) + use_upi(global_iqpi); +} + +// Data with address-discriminated qualifiers. + +// CHECK-LABEL: define void @test_store_data_a_constant() +void test_store_data_a_constant() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @external_int to i64), i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[T0:%.*]] = inttoptr i64 [[SIGN]] to ptr +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * AQ aqpi = &external_int; +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @external_int to i64), i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[T0:%.*]] = inttoptr i64 [[SIGN]] to ptr +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpi = &external_int; +} + +// CHECK-LABEL: define void @test_store_data_au() +void test_store_data_au() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upi, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[T0]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * AQ aqpi = global_upi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upi, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[T0]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpi = global_upi; +} + +// CHECK-LABEL: define void @test_store_data_ai() +void test_store_data_ai() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * AQ aqpi = global_iqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpi = global_iqpi; +} + +// CHECK-LABEL: define void @test_store_data_aa_same() +void test_store_data_aa_same() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * AQ aqpi = global_aqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpi = global_aqpi; +} + +// CHECK-LABEL: define void @test_store_data_aa_different() +void test_store_data_aa_different() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 100) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * DIFF_AQ aqpi = global_aqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 100) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpi = global_aqpi; +} + +// CHECK-LABEL: define void @test_store_data_aa_zero() +void test_store_data_aa_zero() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[NEWDISC:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int * ZERO_AQ aqpi = global_aqpi; +// CHECK: [[LOAD:%.*]] = load ptr, ptr [[V]], +// CHECK-NEXT: [[OLDDISC:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr @global_aqpi, + global_aqpi = aqpi; +} + +// CHECK-LABEL: define void @test_load_data_a() +void test_load_data_a() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 1, i64 [[OLDDISC]]) +// CHECK-NEXT: [[AUTHED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[AUTHED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + int *upi = global_aqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 1, i64 [[OLDDISC]]) +// CHECK-NEXT: [[AUTHED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[AUTHED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + upi = global_aqpi; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpi to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[T0]], i32 1, i64 [[OLDDISC]]) +// CHECK-NEXT: [[AUTHED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[AUTHED]], {{.*}} ] +// CHECK-NEXT: call void @use_upi(ptr noundef [[T0]]) + use_upi(global_aqpi); +} + +// Function with address-independent qualifiers. + +// CHECK-LABEL: define void @test_store_function_i_constant() +void test_store_function_i_constant() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @external_func, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 1, i64 50) +// CHECK-NEXT: [[T0:%.*]] = inttoptr i64 [[SIGN]] to ptr +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * IQ iqpf = &external_func; +// CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @external_func, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 1, i64 50) +// CHECK-NEXT: [[T0:%.*]] = inttoptr i64 [[SIGN]] to ptr +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + iqpf = &external_func; +} + +// CHECK-LABEL: define void @test_store_function_iu() +void test_store_function_iu() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upf, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 0, i64 18983, i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * IQ iqpf = global_upf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upf, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 0, i64 18983, i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + iqpf = global_upf; +} + +// CHECK-LABEL: define void @test_store_function_ia() +void test_store_function_ia() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * IQ iqpf = global_aqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + iqpf = global_aqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 50) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[RESULT:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[RESULT]], ptr [[V]], +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[RESULT]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[RESULT]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 0, i64 18983) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: call void @use_upf(ptr noundef [[T0]]) + use_upf(iqpf = global_aqpf); +} + +// CHECK-LABEL: define void @test_store_function_ii_same() +void test_store_function_ii_same() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: store ptr [[LOAD]], ptr [[V]], + func_t * IQ iqpf = global_iqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: store ptr [[LOAD]], ptr [[V]], + iqpf = global_iqpf; +} + +// CHECK-LABEL: define void @test_store_function_ii_different() +void test_store_function_ii_different() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 100) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * DIFF_IQ iqpf = global_iqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 100) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + iqpf = global_iqpf; +} + +// CHECK-LABEL: define void @test_load_function_i() +void test_load_function_i() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 0, i64 18983) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t *upf = global_iqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 0, i64 18983) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + upf = global_iqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 0, i64 18983) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: call void @use_upf(ptr noundef [[T0]]) + use_upf(global_iqpf); +} + +// Function with address-discriminated qualifiers. + +// CHECK-LABEL: define void @test_store_function_a_constant() +void test_store_function_a_constant() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @external_func, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[T0:%.*]] = inttoptr i64 [[SIGN]] to ptr +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * AQ aqpf = &external_func; +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @external_func, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[T0:%.*]] = inttoptr i64 [[SIGN]] to ptr +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpf = &external_func; +} + +// CHECK-LABEL: define void @test_store_function_au() +void test_store_function_au() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upf, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 0, i64 18983, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * AQ aqpf = global_upf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upf, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 0, i64 18983, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpf = global_upf; +} + +// CHECK-LABEL: define void @test_store_function_ai() +void test_store_function_ai() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * AQ aqpf = global_iqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 50, i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpf = global_iqpf; +} + +// CHECK-LABEL: define void @test_store_function_aa_same() +void test_store_function_aa_same() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * AQ aqpf = global_aqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpf = global_aqpf; +} + +// CHECK-LABEL: define void @test_store_function_aa_different() +void test_store_function_aa_different() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 100) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t * DIFF_AQ aqpf = global_aqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 +// CHECK-NEXT: [[NEWDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T0]], i64 100) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 1, i64 [[NEWDISC]]) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + aqpf = global_aqpf; +} + +// CHECK-LABEL: define void @test_load_function_a() +void test_load_function_a() { +// CHECK: [[V:%.*]] = alloca ptr, +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 0, i64 18983) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + func_t *upf = global_aqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 0, i64 18983) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: store ptr [[T0]], ptr [[V]], + upf = global_aqpf; +// CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, +// CHECK-NEXT: [[OLDDISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @global_aqpf to i64), i64 50) +// CHECK-NEXT: [[T0:%.*]] = icmp ne ptr [[LOAD]], null +// CHECK-NEXT: br i1 [[T0]], +// CHECK: [[T0:%.*]] = ptrtoint ptr [[LOAD]] to i64 +// CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[T0]], i32 1, i64 [[OLDDISC]], i32 0, i64 18983) +// CHECK-NEXT: [[SIGNED:%.*]] = inttoptr i64 [[T1]] to ptr +// CHECK-NEXT: br label +// CHECK: [[T0:%.*]] = phi ptr [ null, {{.*}} ], [ [[SIGNED]], {{.*}} ] +// CHECK-NEXT: call void @use_upf(ptr noundef [[T0]]) + use_upf(global_aqpf); +} diff --git a/clang/test/CodeGen/ptrauth-qualifier.c b/clang/test/CodeGen/ptrauth-qualifier.c new file mode 100644 index 0000000000000..5a664d296ce0e --- /dev/null +++ b/clang/test/CodeGen/ptrauth-qualifier.c @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s + +#include + +// Constant initializers for data pointers. +extern int external_int; + +// CHECK: @g1 = global ptr ptrauth (ptr @external_int, i32 1, i64 56) +int * __ptrauth(1,0,56) g1 = &external_int; + +// CHECK: @g2 = global ptr ptrauth (ptr @external_int, i32 1, i64 1272, ptr @g2) +int * __ptrauth(1,1,1272) g2 = &external_int; + +// CHECK: @g3 = global ptr null +int * __ptrauth(1,1,871) g3 = 0; + +// FIXME: should we make a ptrauth constant for this absolute symbol? +// CHECK: @g4 = global ptr inttoptr (i64 1230 to ptr) +int * __ptrauth(1,1,1902) g4 = (int*) 1230; + +// CHECK: @ga = global [3 x ptr] [ +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 712, ptr @ga), +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 712, ptr getelementptr inbounds ([3 x ptr], ptr @ga, i32 0, i32 1)), +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 712, ptr getelementptr inbounds ([3 x ptr], ptr @ga, i32 0, i32 2))] +int * __ptrauth(1,1,712) ga[3] = { &external_int, &external_int, &external_int }; + +struct A { + int * __ptrauth(1,0,431) f0; + int * __ptrauth(1,0,9182) f1; + int * __ptrauth(1,0,783) f2; +}; + +// CHECK: @gs1 = global %struct.A { +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 431), +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 9182), +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 783) } +struct A gs1 = { &external_int, &external_int, &external_int }; + +struct B { + int * __ptrauth(1,1,1276) f0; + int * __ptrauth(1,1,23674) f1; + int * __ptrauth(1,1,163) f2; +}; + +// CHECK: @gs2 = global %struct.B { +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 1276, ptr @gs2), +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 23674, ptr getelementptr inbounds (%struct.B, ptr @gs2, i32 0, i32 1)), +// CHECK-SAME: ptr ptrauth (ptr @external_int, i32 1, i64 163, ptr getelementptr inbounds (%struct.B, ptr @gs2, i32 0, i32 2)) } +struct B gs2 = { &external_int, &external_int, &external_int }; + +// Constant initializers for function pointers. +extern void external_function(void); +typedef void (*fpt)(void); + +// CHECK: @f1 = global ptr ptrauth (ptr @external_function, i32 1, i64 56) +fpt __ptrauth(1,0,56) f1 = &external_function; + +// CHECK: @f2 = global ptr ptrauth (ptr @external_function, i32 1, i64 1272, ptr @f2) +fpt __ptrauth(1,1,1272) f2 = &external_function; + +// CHECK: @fa = global [3 x ptr] [ +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 712, ptr @fa), +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 712, ptr getelementptr inbounds ([3 x ptr], ptr @fa, i32 0, i32 1)), +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 712, ptr getelementptr inbounds ([3 x ptr], ptr @fa, i32 0, i32 2))] +fpt __ptrauth(1,1,712) fa[3] = { &external_function, &external_function, &external_function }; + +struct C { + fpt __ptrauth(1,0,431) f0; + fpt __ptrauth(1,0,9182) f1; + fpt __ptrauth(1,0,783) f2; +}; +// CHECK: @fs1 = global %struct.C { +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 431), +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 9182), +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 783) } +struct C fs1 = { &external_function, &external_function, &external_function }; + +struct D { + fpt __ptrauth(1,1,1276) f0; + fpt __ptrauth(1,1,23674) f1; + fpt __ptrauth(1,1,163) f2; +}; +// CHECK: @fs2 = global %struct.D { +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 1276, ptr @fs2), +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 23674, ptr getelementptr inbounds (%struct.D, ptr @fs2, i32 0, i32 1)), +// CHECK-SAME: ptr ptrauth (ptr @external_function, i32 1, i64 163, ptr getelementptr inbounds (%struct.D, ptr @fs2, i32 0, i32 2)) } +struct D fs2 = { &external_function, &external_function, &external_function }; diff --git a/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp b/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp new file mode 100644 index 0000000000000..d38289cd7cef7 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp @@ -0,0 +1,167 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -std=c++11 -emit-llvm %s -o - | FileCheck %s + +#define AQ __ptrauth(1,1,50) +#define IQ __ptrauth(1,0,50) + +// CHECK: %[[STRUCT_SA:.*]] = type { ptr, ptr } +// CHECK: %[[STRUCT_SI:.*]] = type { ptr } + +struct SA { + int * AQ m0; // Signed using address discrimination. + int * AQ m1; // Signed using address discrimination. +}; + +struct SI { + int * IQ m; // No address discrimination. +}; + +struct __attribute__((trivial_abi)) TrivialSA { + int * AQ m0; // Signed using address discrimination. + int * AQ m1; // Signed using address discrimination. +}; + +// Check that TrivialSA is passed indirectly despite being annotated with +// 'trivial_abi'. + +// CHECK: define void @_Z18testParamTrivialSA9TrivialSA(ptr noundef %{{.*}}) + +void testParamTrivialSA(TrivialSA a) { +} + +// CHECK: define void @_Z19testCopyConstructor2SA(ptr +// CHECK: call noundef ptr @_ZN2SAC1ERKS_( + +// CHECK: define linkonce_odr noundef ptr @_ZN2SAC1ERKS_( +// CHECK: call noundef ptr @_ZN2SAC2ERKS_( + +void testCopyConstructor(SA a) { + SA t = a; +} + +// CHECK: define void @_Z19testMoveConstructor2SA(ptr +// CHECK: call noundef ptr @_ZN2SAC1EOS_( + +// CHECK: define linkonce_odr noundef ptr @_ZN2SAC1EOS_( +// CHECK: call noundef ptr @_ZN2SAC2EOS_( + +void testMoveConstructor(SA a) { + SA t = static_cast(a); +} + +// CHECK: define void @_Z18testCopyAssignment2SA(ptr +// CHECK: call noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSERKS_( + +// CHECK: define linkonce_odr noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSERKS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 +// CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 +// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 +// CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 +// CHECK: %[[THISI:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 +// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THISI]], i32 0, i32 0 +// CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 +// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 +// CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 +// CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) +// CHECK: %[[V5:.*]] = ptrtoint ptr %[[M0]] to i64 +// CHECK: %[[V6:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V5]], i64 50) +// CHECK: %[[V8:.*]] = ptrtoint ptr %[[V2]] to i64 +// CHECK: %[[V9:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V8]], i32 1, i64 %[[V4]], i32 1, i64 %[[V6]]) + +void testCopyAssignment(SA a) { + SA t; + t = a; +} + +// CHECK: define void @_Z18testMoveAssignment2SA(ptr +// CHECK: call noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSEOS_( + +// CHECK: define linkonce_odr noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSEOS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 +// CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 +// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 +// CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 +// CHECK: %[[THISI:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 +// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THISI]], i32 0, i32 0 +// CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 +// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 +// CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 +// CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) +// CHECK: %[[V5:.*]] = ptrtoint ptr %[[M0]] to i64 +// CHECK: %[[V6:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V5]], i64 50) +// CHECK: %[[V8:.*]] = ptrtoint ptr %[[V2]] to i64 +// CHECK: %[[V9:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V8]], i32 1, i64 %[[V4]], i32 1, i64 %[[V6]]) + +void testMoveAssignment(SA a) { + SA t; + t = static_cast(a); +} + +// CHECK: define void @_Z19testCopyConstructor2SI(i +// CHECK: call void @llvm.memcpy.p0.p0.i64( + +void testCopyConstructor(SI a) { + SI t = a; +} + +// CHECK: define void @_Z19testMoveConstructor2SI( +// CHECK: call void @llvm.memcpy.p0.p0.i64( + +void testMoveConstructor(SI a) { + SI t = static_cast(a); +} + +// CHECK: define void @_Z18testCopyAssignment2SI( +// CHECK: call void @llvm.memcpy.p0.p0.i64( + +void testCopyAssignment(SI a) { + SI t; + t = a; +} + +// CHECK: define void @_Z18testMoveAssignment2SI( +// CHECK: call void @llvm.memcpy.p0.p0.i64( + +void testMoveAssignment(SI a) { + SI t; + t = static_cast(a); +} + +// CHECK: define linkonce_odr noundef ptr @_ZN2SAC2ERKS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// CHECK: %[[RETVAL:.*]] = alloca ptr, align 8 +// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 +// CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 +// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 +// CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 +// CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 +// CHECK: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 +// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 +// CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 +// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 +// CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 +// CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) +// CHECK: %[[V5:.*]] = ptrtoint ptr %[[M0]] to i64 +// CHECK: %[[V6:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V5]], i64 50) +// CHECK: %[[V8:.*]] = ptrtoint ptr %[[V2]] to i64 +// CHECK: %[[V9:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V8]], i32 1, i64 %[[V4]], i32 1, i64 %[[V6]]) + +// CHECK: define linkonce_odr noundef ptr @_ZN2SAC2EOS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// CHECK: %[[RETVAL:.*]] = alloca ptr, align 8 +// CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 +// CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 +// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 +// CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 +// CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 +// CHECK: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 +// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 +// CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 +// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 +// CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 +// CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) +// CHECK: %[[V5:.*]] = ptrtoint ptr %[[M0]] to i64 +// CHECK: %[[V6:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V5]], i64 50) +// CHECK: %[[V8:.*]] = ptrtoint ptr %[[V2]] to i64 +// CHECK: %[[V9:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V8]], i32 1, i64 %[[V4]], i32 1, i64 %[[V6]]) diff --git a/clang/test/CodeGenObjCXX/ptrauth-struct-cxx-abi.mm b/clang/test/CodeGenObjCXX/ptrauth-struct-cxx-abi.mm new file mode 100644 index 0000000000000..e5cb71bad47c0 --- /dev/null +++ b/clang/test/CodeGenObjCXX/ptrauth-struct-cxx-abi.mm @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fptrauth-calls -fptrauth-intrinsics -std=c++11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s + +#define AQ __ptrauth(1,1,50) + +struct AddrDiscStrong0 { + int * AQ f0; // Signed using address discrimination. + __strong id f1; +}; + +struct AddrDiscStrong1 { + AddrDiscStrong1(const AddrDiscStrong1 &); + int * AQ f0; // Signed using address discrimination. + __strong id f1; +}; + +// Check that AddrDiscStrong0 is destructed in the callee. + +// CHECK: define void @_Z24testParamAddrDiscStrong015AddrDiscStrong0(ptr noundef %[[A:.*]]) +// CHECK: call noundef ptr @_ZN15AddrDiscStrong0D1Ev(ptr noundef nonnull align {{[0-9]+}} dereferenceable(16) %[[A]]) +// CHECK: ret void + +// CHECK: define linkonce_odr noundef ptr @_ZN15AddrDiscStrong0D1Ev( + +void testParamAddrDiscStrong0(AddrDiscStrong0 a) { +} + +// Check that AddrDiscStrong1 is not destructed in the callee because it has a +// non-trivial copy constructor. + +// CHECK: define void @_Z24testParamAddrDiscStrong115AddrDiscStrong1(ptr noundef %{{.*}}) +// CHECK-NOT: call +// CHECK: ret void + +void testParamAddrDiscStrong1(AddrDiscStrong1 a) { +} diff --git a/clang/test/Preprocessor/ptrauth_feature.c b/clang/test/Preprocessor/ptrauth_feature.c index 14059f827b94c..14ef80860d0e9 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -85,6 +85,8 @@ void has_ptrauth_type_info_vtable_pointer_discrimination() {} void no_ptrauth_type_info_vtable_pointer_discrimination() {} #endif +#include + #if __has_feature(ptrauth_function_pointer_type_discrimination) // FUNC: has_ptrauth_function_pointer_type_discrimination void has_ptrauth_function_pointer_type_discrimination() {} @@ -108,3 +110,11 @@ void has_ptrauth_indirect_gotos() {} // NOGOTOS: no_ptrauth_indirect_gotos void no_ptrauth_indirect_gotos() {} #endif + +#if __has_feature(ptrauth_qualifier) +// INTRIN: has_ptrauth_qualifier +void has_ptrauth_qualifier() {} +#else +// NOINTRIN: no_ptrauth_qualifier +void no_ptrauth_qualifier() {} +#endif diff --git a/clang/test/Sema/atomic-ops-ptrauth.c b/clang/test/Sema/atomic-ops-ptrauth.c new file mode 100644 index 0000000000000..65b58379c8552 --- /dev/null +++ b/clang/test/Sema/atomic-ops-ptrauth.c @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s + +#include + +int i; +int *__ptrauth(2, 1, 100) authenticated_ptr = &i; +int *__ptrauth(2, 0, 200) non_addr_discriminatedauthenticated_ptr = &i; +int * wat = &i; +#define ATOMIZE(p) (__typeof__(p) volatile _Atomic *)(long)(&p) + +void f() { + static int j = 1; + __c11_atomic_init(ATOMIZE(authenticated_ptr), 5); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __c11_atomic_store(ATOMIZE(authenticated_ptr), 0, memory_order_relaxed); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __c11_atomic_load(ATOMIZE(authenticated_ptr), memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __c11_atomic_store(ATOMIZE(authenticated_ptr), 1, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_store_n(ATOMIZE(authenticated_ptr), 4, memory_order_release); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_store(ATOMIZE(authenticated_ptr), j, memory_order_release); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __c11_atomic_exchange(ATOMIZE(authenticated_ptr), 1, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_exchange(ATOMIZE(authenticated_ptr), &j, &j, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __c11_atomic_fetch_add(ATOMIZE(authenticated_ptr), 1, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_fetch_add(ATOMIZE(authenticated_ptr), 3, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_fetch_sub(ATOMIZE(authenticated_ptr), 3, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_fetch_min(ATOMIZE(authenticated_ptr), 3, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_fetch_max(ATOMIZE(authenticated_ptr), 3, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __c11_atomic_fetch_and(ATOMIZE(authenticated_ptr), 1, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_fetch_and(ATOMIZE(authenticated_ptr), 3, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_fetch_or(ATOMIZE(authenticated_ptr), 3, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + __atomic_fetch_xor(ATOMIZE(authenticated_ptr), 3, memory_order_seq_cst); + // expected-error@-1 {{address argument to atomic operation must be a pointer to a non address discriminated type ('volatile __ptrauth(2,1,100) _Atomic(int *) *' invalid)}} + + __c11_atomic_init(ATOMIZE(non_addr_discriminatedauthenticated_ptr), &j); + __c11_atomic_store(ATOMIZE(non_addr_discriminatedauthenticated_ptr), 0, memory_order_relaxed); + __c11_atomic_load(ATOMIZE(non_addr_discriminatedauthenticated_ptr), memory_order_seq_cst); + __atomic_store(&j, ATOMIZE(non_addr_discriminatedauthenticated_ptr), memory_order_release); + // expected-warning@-1 {{incompatible pointer types passing 'volatile __ptrauth(2,0,200) _Atomic(int *) *' to parameter of type 'int *'}} + __c11_atomic_exchange(ATOMIZE(j), ATOMIZE(non_addr_discriminatedauthenticated_ptr), memory_order_seq_cst); + // expected-error@-1 {{incompatible pointer to integer conversion passing 'volatile __ptrauth(2,0,200) _Atomic(int *) *' to parameter of type 'typeof (j)' (aka 'int')}} + __c11_atomic_fetch_add(ATOMIZE(non_addr_discriminatedauthenticated_ptr), ATOMIZE(j), memory_order_seq_cst); + // expected-error@-1 {{incompatible pointer to integer conversion passing 'volatile _Atomic(typeof (j)) *' to parameter of type 'long'}} + __c11_atomic_fetch_and(ATOMIZE(j), ATOMIZE(non_addr_discriminatedauthenticated_ptr), memory_order_seq_cst); + // expected-error@-1 {{incompatible pointer to integer conversion passing 'volatile __ptrauth(2,0,200) _Atomic(int *) *' to parameter of type 'typeof (j)' (aka 'int')}} + + + __sync_fetch_and_add(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_fetch_and_sub(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_fetch_and_or(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_fetch_and_and(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_fetch_and_xor(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_fetch_and_nand(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + + __sync_add_and_fetch(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_sub_and_fetch(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_or_and_fetch(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_and_and_fetch(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_xor_and_fetch(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_nand_and_fetch(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + + __sync_bool_compare_and_swap(&authenticated_ptr, 1, 0); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_val_compare_and_swap(&authenticated_ptr, 1, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + + __sync_lock_test_and_set(&authenticated_ptr, 1); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + __sync_lock_release(&authenticated_ptr); + // expected-error@-1 {{address argument to __sync operation must be a pointer to a non address discriminated type ('int *__ptrauth(2,1,100)' invalid)}} + + +int i = 0; + + __sync_fetch_and_add(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_fetch_and_sub(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_fetch_and_or(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_fetch_and_and(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_fetch_and_xor(&non_addr_discriminatedauthenticated_ptr, &i); + + __sync_add_and_fetch(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_sub_and_fetch(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_or_and_fetch(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_and_and_fetch(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_xor_and_fetch(&non_addr_discriminatedauthenticated_ptr, &i); + + __sync_bool_compare_and_swap(&non_addr_discriminatedauthenticated_ptr, &i, &i); + __sync_val_compare_and_swap(&non_addr_discriminatedauthenticated_ptr, &i, &i); + + __sync_lock_test_and_set(&non_addr_discriminatedauthenticated_ptr, &i); + __sync_lock_release(&non_addr_discriminatedauthenticated_ptr); +} diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c new file mode 100644 index 0000000000000..02e511a08ddeb --- /dev/null +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s + +#include + +#if __has_feature(ptrauth_qualifier) +#warning __ptrauth qualifier enabled! +// expected-warning@-1 {{__ptrauth qualifier enabled!}} +#endif + +#if __aarch64__ +#define VALID_CODE_KEY 0 +#define VALID_DATA_KEY 2 +#define INVALID_KEY 200 +#else +#error Provide these constants if you port this test +#endif + +int * __ptrauth(VALID_DATA_KEY) valid0; + +typedef int *intp; + +int nonConstantGlobal = 5; + +__ptrauth int invalid0; // expected-error{{expected '('}} +__ptrauth() int invalid1; // expected-error{{expected expression}} +__ptrauth(INVALID_KEY) int invalid2; // expected-error{{200 does not identify a valid pointer authentication key for the current target}} +__ptrauth(VALID_DATA_KEY) int invalid3; // expected-error{{__ptrauth qualifier may only be applied to pointer types}} +__ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error{{__ptrauth qualifier may only be applied to pointer types}} +int * (__ptrauth(VALID_DATA_KEY) invalid5); // expected-error{{expected identifier or '('}} expected-error{{expected ')'}} expected-note {{to match this '('}} +int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // expected-error{{type 'int *__ptrauth(2,0,0)' is already __ptrauth-qualified}} +int * __ptrauth(VALID_DATA_KEY, 2) invalid7; // expected-error{{address discrimination flag for __ptrauth must be 0 or 1; value is 2}} +int * __ptrauth(VALID_DATA_KEY, -1) invalid8; // expected-error{{address discrimination flag for __ptrauth must be 0 or 1; value is -1}} +int * __ptrauth(VALID_DATA_KEY, 1, -1) invalid9; // expected-error{{extra discriminator for __ptrauth must be between 0 and 65535; value is -1}} +int * __ptrauth(VALID_DATA_KEY, 1, 100000) invalid10; // expected-error{{extra discriminator for __ptrauth must be between 0 and 65535; value is 100000}} +int * __ptrauth(VALID_DATA_KEY, 1, nonConstantGlobal) invalid12; // expected-error{{argument to __ptrauth must be an integer constant expression}} + +int * __ptrauth(VALID_DATA_KEY) valid0; +int * __ptrauth(VALID_DATA_KEY) *valid1; +__ptrauth(VALID_DATA_KEY) intp valid2; +__ptrauth(VALID_DATA_KEY) intp *valid3; +intp __ptrauth(VALID_DATA_KEY) valid4; +intp __ptrauth(VALID_DATA_KEY) *valid5; +int * __ptrauth(VALID_DATA_KEY, 0) valid6; +int * __ptrauth(VALID_DATA_KEY, 1) valid7; +int * __ptrauth(VALID_DATA_KEY, (_Bool) 1) valid8; +int * __ptrauth(VALID_DATA_KEY, 1, 0) valid9; +int * __ptrauth(VALID_DATA_KEY, 1, 65535) valid10; + +extern intp redeclaration0; // expected-note {{previous declaration}} +extern intp __ptrauth(VALID_DATA_KEY) redeclaration0; // expected-error{{redeclaration of 'redeclaration0' with a different type: '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)') vs 'intp' (aka 'int *')}} + +extern intp redeclaration1; // expected-note {{previous declaration}} +extern intp __ptrauth(VALID_DATA_KEY) redeclaration1; // expected-error{{redeclaration of 'redeclaration1' with a different type: '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)') vs 'intp' (aka 'int *')}} + +intp __ptrauth(VALID_DATA_KEY) redeclaration2; // expected-note {{previous definition}} +intp redeclaration2 = 0; // expected-error{{redefinition of 'redeclaration2' with a different type: 'intp' (aka 'int *') vs '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} + +intp __ptrauth(VALID_DATA_KEY) redeclaration3; // expected-note {{previous definition}} +intp redeclaration3 = 0; // expected-error{{redefinition of 'redeclaration3' with a different type: 'intp' (aka 'int *') vs '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} + +void illegal0(intp __ptrauth(VALID_DATA_KEY)); // expected-error{{parameter types may not be qualified with __ptrauth}} +intp __ptrauth(VALID_DATA_KEY) illegal1(void); // expected-error{{return types may not be qualified with __ptrauth}} + +void test_code(intp p) { + p = (intp __ptrauth(VALID_DATA_KEY)) 0; // expected-error{{cast types may not be qualified with __ptrauth}} + + __ptrauth(VALID_DATA_KEY) intp pSpecial = p; + pSpecial = p; + intp pNormal = pSpecial; + pNormal = pSpecial; + + intp __ptrauth(VALID_DATA_KEY) *ppSpecial0 = &pSpecial; + intp __ptrauth(VALID_DATA_KEY) *ppSpecial1 = &pNormal; // expected-error {{initializing '__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') with an expression of type 'intp *' (aka 'int **') changes pointer-authentication of pointee type}} + intp *ppNormal0 = &pSpecial; // expected-error {{initializing 'intp *' (aka 'int **') with an expression of type '__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') changes pointer-authentication of pointee type}} + intp *ppNormal1 = &pNormal; + + intp *pp5 = (p ? &pSpecial : &pNormal); // expected-error {{__ptrauth qualification mismatch ('__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') and 'intp *' (aka 'int **'))}} +} + +void test_array(void) { + intp __ptrauth(VALID_DATA_KEY) pSpecialArray[10]; + intp __ptrauth(VALID_DATA_KEY) *ppSpecial0 = pSpecialArray; + intp __ptrauth(VALID_DATA_KEY) *ppSpecial1 = &pSpecialArray[0]; +} diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp new file mode 100644 index 0000000000000..2cd9ebe356f61 --- /dev/null +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -0,0 +1,141 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++11 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s + +#define AQ __ptrauth(1,1,50) +#define AQ2 __ptrauth(1,1,51) +#define IQ __ptrauth(1,0,50) + +struct __attribute__((trivial_abi)) AddrDisc { // expected-warning {{'trivial_abi' cannot be applied to 'AddrDisc'}} expected-note {{'trivial_abi' is disallowed on 'AddrDisc' because it has an address-discriminated __ptrauth field}} + int * AQ m0; +}; + +struct __attribute__((trivial_abi)) NoAddrDisc { + int * IQ m0; +}; + +namespace test_union { + + union U0 { + int * AQ f0; // expected-note 4 {{'U0' is implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + + // ptrauth fields that don't have an address-discriminated qualifier don't + // delete the special functions. + int * IQ f1; + }; + + union U1 { + int * AQ f0; // expected-note 8 {{'U1' is implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + U1() = default; + ~U1() = default; + U1(const U1 &) = default; // expected-warning {{explicitly defaulted copy constructor is implicitly deleted}} expected-note 2 {{explicitly defaulted function was implicitly deleted here}} expected-note{{replace 'default'}} + U1(U1 &&) = default; // expected-warning {{explicitly defaulted move constructor is implicitly deleted}} expected-note{{replace 'default'}} + U1 & operator=(const U1 &) = default; // expected-warning {{explicitly defaulted copy assignment operator is implicitly deleted}} expected-note 2 {{explicitly defaulted function was implicitly deleted here}} expected-note{{replace 'default'}} + U1 & operator=(U1 &&) = default; // expected-warning {{explicitly defaulted move assignment operator is implicitly deleted}} expected-note{{replace 'default'}} + }; + + // It's fine if the user has explicitly defined the special functions. + union U2 { + int * AQ f0; + U2() = default; + ~U2() = default; + U2(const U2 &); + U2(U2 &&); + U2 & operator=(const U2 &); + U2 & operator=(U2 &&); + }; + + // Address-discriminated ptrauth fields in anonymous union fields delete the + // defaulted copy/move constructors/assignment operators of the containing + // class. + struct S0 { + union { + int * AQ f0; // expected-note 4 {{' is implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + char f1; + }; + }; + + struct S1 { + union { + union { + int * AQ f0; // expected-note 4 {{implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + char f1; + } u; // expected-note 4 {{'S1' is implicitly deleted because field 'u' has a deleted}} + int f2; + }; + }; + + U0 *x0; + U1 *x1; + U2 *x2; + S0 *x3; + S1 *x4; + + // No diagnostics since constructors/destructors of the unions aren't deleted by default. + void testDefaultConstructor() { + U0 u0; + U1 u1; + U2 u2; + S0 s0; + S1 s1; + } + + // No diagnostics since destructors of the unions aren't deleted by default. + void testDestructor(U0 *u0, U1 *u1, U2 *u2, S0 *s0, S1 *s1) { + delete u0; + delete u1; + delete u2; + delete s0; + delete s1; + } + + void testCopyConstructor(U0 *u0, U1 *u1, U2 *u2, S0 *s0, S1 *s1) { + U0 t0(*u0); // expected-error {{call to implicitly-deleted copy constructor}} + U1 t1(*u1); // expected-error {{call to implicitly-deleted copy constructor}} + U2 t2(*u2); + S0 t3(*s0); // expected-error {{call to implicitly-deleted copy constructor}} + S1 t4(*s1); // expected-error {{call to implicitly-deleted copy constructor}} + } + + void testCopyAssignment(U0 *u0, U1 *u1, U2 *u2, S0 *s0, S1 *s1) { + *x0 = *u0; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + *x1 = *u1; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + *x2 = *u2; + *x3 = *s0; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + *x4 = *s1; // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + } + + void testMoveConstructor(U0 *u0, U1 *u1, U2 *u2, S0 *s0, S1 *s1) { + U0 t0(static_cast(*u0)); // expected-error {{call to implicitly-deleted copy constructor}} + U1 t1(static_cast(*u1)); // expected-error {{call to implicitly-deleted copy constructor}} + U2 t2(static_cast(*u2)); + S0 t3(static_cast(*s0)); // expected-error {{call to implicitly-deleted copy constructor}} + S1 t4(static_cast(*s1)); // expected-error {{call to implicitly-deleted copy constructor}} + } + + void testMoveAssignment(U0 *u0, U1 *u1, U2 *u2, S0 *s0, S1 *s1) { + *x0 = static_cast(*u0); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + *x1 = static_cast(*u1); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + *x2 = static_cast(*u2); + *x3 = static_cast(*s0); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + *x4 = static_cast(*s1); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} + } +} + +bool test_composite_type0(bool c, int * AQ * a0, int * AQ * a1) { + auto t = c ? a0 : a1; + return a0 == a1; +} + +bool test_composite_type1(bool c, int * AQ * a0, int * AQ2 * a1) { + auto t = c ? a0 : a1; // expected-error {{incompatible operand types ('int *__ptrauth(1,1,50) *' and 'int *__ptrauth(1,1,51) *')}} + return a0 == a1; // expected-error {{comparison of distinct pointer types ('int *__ptrauth(1,1,50) *' and 'int *__ptrauth(1,1,51) *')}} +} + +void test_bad_call_diag(void *AQ *ptr); // expected-note{{candidate function not viable: 1st argument ('void *__ptrauth(1,1,51) *') has __ptrauth(1,1,51) qualifier, but parameter has __ptrauth(1,1,50) qualifier}} expected-note{{candidate function not viable: 1st argument ('void **') has no ptrauth qualifier, but parameter has __ptrauth(1,1,50) qualifier}} +void test_bad_call_diag2(void **ptr); // expected-note{{1st argument ('void *__ptrauth(1,1,50) *') has __ptrauth(1,1,50) qualifier, but parameter has no ptrauth qualifier}} + +int test_call_diag() { + void *AQ ptr1, *AQ2 ptr2, *ptr3; + test_bad_call_diag(&ptr2); // expected-error {{no matching function for call to 'test_bad_call_diag'}} + test_bad_call_diag(&ptr3); // expected-error {{no matching function for call to 'test_bad_call_diag'}} + test_bad_call_diag2(&ptr1); // expected-error {{no matching function for call to 'test_bad_call_diag2'}} +} diff --git a/clang/test/SemaCXX/ptrauth-template-parameters.cpp b/clang/test/SemaCXX/ptrauth-template-parameters.cpp new file mode 100644 index 0000000000000..2b09b70046d53 --- /dev/null +++ b/clang/test/SemaCXX/ptrauth-template-parameters.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple arm64e-apple-ios -fsyntax-only -verify -fptrauth-intrinsics -std=c++20 %s + +template struct G { + T __ptrauth(0,0,1234) test; + // expected-error@-1 2 {{type '__ptrauth(0,0,1234) T' is already __ptrauth-qualified}} +}; + +template struct Indirect { + G layers; + // expected-note@-1{{in instantiation of template class 'G' requested here}} + // expected-note@-2{{in instantiation of template class 'G' requested here}} +}; + +void f3() { + Indirect one; + // expected-note@-1{{in instantiation of template class 'Indirect' requested here}} + Indirect two; + // expected-note@-1{{in instantiation of template class 'Indirect' requested here}} + Indirect three; +} diff --git a/clang/test/SemaObjC/ptrauth-qualifier.m b/clang/test/SemaObjC/ptrauth-qualifier.m new file mode 100644 index 0000000000000..e5d424eaf92fd --- /dev/null +++ b/clang/test/SemaObjC/ptrauth-qualifier.m @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s + +#if __has_feature(ptrauth_qualifier) +#warning __ptrauth qualifier enabled! +// expected-warning@-1 {{__ptrauth qualifier enabled!}} +#endif + +@interface Foo +// expected-warning@-1 {{class 'Foo' defined without specifying a base class}} +// expected-note@-2 {{add a super class to fix this problem}} + +@property void *__ptrauth(1, 1, 1) invalid1; +// expected-error@-1 {{properties may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} + +@property void *__ptrauth(1, 0, 1) invalid2; +// expected-error@-1 {{properties may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} + +- (void *__ptrauth(1, 1, 1))invalid5; +// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} + +- (void *__ptrauth(1, 0, 1))invalid6; +// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} + +- (void)invalid9:(void *__ptrauth(1, 1, 1))a; +// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} +// expected-note@-2 {{method 'invalid9:' declared here}} + +- (void)invalid10:(void *__ptrauth(1, 0, 1))a; +// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} +// expected-note@-2 {{method 'invalid10:' declared here}} + +@end + +@implementation Foo +// expected-warning@-1 2{{method definition for}} + +- (void *__ptrauth(1, 1, 1))invalid13 { +// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} + return 0; +} + +- (void *__ptrauth(1, 0, 1))invalid14 { +// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} + return 0; +} + +- (void)invalid17:(void *__ptrauth(1, 1, 1))a { +// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} +} + +- (void)invalid18:(void *__ptrauth(1, 0, 1))a { +// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} +} + +@end From d0021eaedd31eac054ab2782be4c5f37b7416dd1 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 26 Jul 2024 17:04:08 -0700 Subject: [PATCH 02/19] Fix coding style violations --- clang/include/clang/Sema/Sema.h | 4 +- clang/lib/AST/ItaniumMangle.cpp | 8 +-- clang/lib/AST/TypePrinter.cpp | 8 +-- clang/lib/CodeGen/CGDecl.cpp | 12 ++-- clang/lib/CodeGen/CGExpr.cpp | 28 ++++---- clang/lib/CodeGen/CGExprConstant.cpp | 8 +-- clang/lib/CodeGen/CGExprScalar.cpp | 16 ++--- clang/lib/CodeGen/CGPointerAuth.cpp | 98 ++++++++++++++-------------- clang/lib/CodeGen/CodeGenFunction.h | 32 ++++----- clang/lib/Parse/ParseDecl.cpp | 20 +++--- clang/lib/Sema/SemaChecking.cpp | 52 +++++++-------- clang/lib/Sema/SemaType.cpp | 48 +++++++------- 12 files changed, 167 insertions(+), 167 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 211d3941921ff..673862e4711a4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3468,8 +3468,8 @@ class Sema final : public SemaBase { PADAK_ExtraDiscPtrAuth, }; - bool checkPointerAuthDiscriminatorArg(Expr *arg, PointerAuthDiscArgKind kind, - unsigned &intVal); + bool checkPointerAuthDiscriminatorArg(Expr *Arg, PointerAuthDiscArgKind Kind, + unsigned &IntVal); /// Diagnose function specifiers on a declaration of an identifier that /// does not identify a function. diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 1b78eeb29f9da..c6c92fb780c18 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2823,7 +2823,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp mangleVendorQualifier("__unaligned"); // __ptrauth. Note that this is parameterized. - if (auto ptrauth = Quals.getPointerAuth()) { + if (auto PtrAuth = Quals.getPointerAuth()) { mangleVendorQualifier("__ptrauth"); // For now, since we only allow non-dependent arguments, we can just // inline the mangling of those arguments as literals. We treat the @@ -2831,13 +2831,13 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp // address-discriminated argument as 'bool'. Out << "I" "Lj" - << ptrauth.getKey() + << PtrAuth.getKey() << "E" "Lb" - << unsigned(ptrauth.isAddressDiscriminated()) + << unsigned(PtrAuth.isAddressDiscriminated()) << "E" "Lj" - << ptrauth.getExtraDiscriminator() + << PtrAuth.getExtraDiscriminator() << "E" "E"; } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index e5fd7b47cb9c2..3598936cd042f 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -2470,8 +2470,8 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)) return false; - if (auto pointerAuth = getPointerAuth()) - if (!pointerAuth.isEmptyWhenPrinted(Policy)) + if (auto PointerAuth = getPointerAuth()) + if (!PointerAuth.isEmptyWhenPrinted(Policy)) return false; return true; @@ -2580,12 +2580,12 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, } } - if (auto pointerAuth = getPointerAuth()) { + if (auto PointerAuth = getPointerAuth()) { if (addSpace) OS << ' '; addSpace = true; - pointerAuth.print(OS, Policy); + PointerAuth.print(OS, Policy); } if (appendSpaceIfNonEmpty && addSpace) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 39330853ce705..c81ad78425c03 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -795,17 +795,17 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, LValue lvalue, bool capturedByInit) { Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime(); if (!lifetime) { - llvm::Value *value; - if (auto ptrauth = lvalue.getQuals().getPointerAuth()) { - value = EmitPointerAuthQualify(ptrauth, init, lvalue.getAddress()); + llvm::Value *Value; + if (auto PtrAuth = lvalue.getQuals().getPointerAuth()) { + Value = EmitPointerAuthQualify(PtrAuth, init, lvalue.getAddress()); lvalue.getQuals().removePointerAuth(); } else { - value = EmitScalarExpr(init); + Value = EmitScalarExpr(init); } if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast(D)); - EmitNullabilityCheck(lvalue, value, init->getExprLoc()); - EmitStoreThroughLValue(RValue::get(value), lvalue, true); + EmitNullabilityCheck(lvalue, Value, init->getExprLoc()); + EmitStoreThroughLValue(RValue::get(Value), lvalue, true); return; } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 43dab7b41b8a1..0d43f824e489e 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2191,10 +2191,10 @@ RValue CodeGenFunction::EmitLoadOfAnyValue(LValue LV, AggValueSlot Slot, /// returning the rvalue. RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { // Load from __ptrauth. - if (auto ptrauth = LV.getQuals().getPointerAuth()) { + if (auto PtrAuth = LV.getQuals().getPointerAuth()) { LV.getQuals().removePointerAuth(); auto value = EmitLoadOfLValue(LV, Loc).getScalarVal(); - return RValue::get(EmitPointerAuthUnqualify(ptrauth, value, LV.getType(), + return RValue::get(EmitPointerAuthUnqualify(PtrAuth, value, LV.getType(), LV.getAddress(), /*known nonnull*/ false)); } @@ -2427,8 +2427,8 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, } // Handle __ptrauth qualification by re-signing the value. - if (auto pointerAuth = Dst.getQuals().getPointerAuth()) { - Src = RValue::get(EmitPointerAuthQualify(pointerAuth, Src.getScalarVal(), + if (auto PointerAuth = Dst.getQuals().getPointerAuth()) { + Src = RValue::get(EmitPointerAuthQualify(PointerAuth, Src.getScalarVal(), Dst.getType(), Dst.getAddress(), /*known nonnull*/ false)); } @@ -5574,21 +5574,21 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) { // Try to remember the original __ptrauth qualifier for loads of // function pointers. if (ICE->getCastKind() == CK_LValueToRValue) { - auto subExpr = ICE->getSubExpr(); - if (auto ptrType = subExpr->getType()->getAs()) { - auto result = EmitOrigPointerRValue(E); + auto *SubExpr = ICE->getSubExpr(); + if (auto *PtrType = SubExpr->getType()->getAs()) { + auto Result = EmitOrigPointerRValue(E); - QualType functionType = ptrType->getPointeeType(); - assert(functionType->isFunctionType()); + QualType FunctionType = PtrType->getPointeeType(); + assert(FunctionType->isFunctionType()); GlobalDecl GD; if (const auto *VD = dyn_cast_or_null(E->getReferencedDeclOfCallee())) { GD = GlobalDecl(VD); } - CGCalleeInfo calleeInfo(functionType->getAs(), GD); - CGCallee callee(calleeInfo, result.first, result.second); - return callee; + CGCalleeInfo CalleeInfo(FunctionType->getAs(), GD); + CGCallee Callee(CalleeInfo, Result.first, Result.second); + return Callee; } } @@ -5654,12 +5654,12 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { switch (getEvaluationKind(E->getType())) { case TEK_Scalar: { - if (auto ptrauth = E->getLHS()->getType().getPointerAuth()) { + if (auto PtrAuth = E->getLHS()->getType().getPointerAuth()) { LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); LValue CopiedLV = LV; CopiedLV.getQuals().removePointerAuth(); llvm::Value *RV = - EmitPointerAuthQualify(ptrauth, E->getRHS(), CopiedLV.getAddress()); + EmitPointerAuthQualify(PtrAuth, E->getRHS(), CopiedLV.getAddress()); EmitNullabilityCheck(CopiedLV, RV, E->getExprLoc()); EmitStoreThroughLValue(RValue::get(RV), CopiedLV); return LV; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index a66e937c9eabc..9cc80c4385d29 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2068,9 +2068,9 @@ llvm::Constant *ConstantLValueEmitter::tryEmit() { } // Apply pointer-auth signing from the destination type. - if (auto pointerAuth = DestType.getPointerAuth()) { + if (auto PointerAuth = DestType.getPointerAuth()) { if (!result.HasDestPointerAuth) { - value = Emitter.tryEmitConstantSignedPointer(value, pointerAuth); + value = Emitter.tryEmitConstantSignedPointer(value, PointerAuth); if (!value) return nullptr; } @@ -2119,9 +2119,9 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { return CGM.GetWeakRefReference(D).getPointer(); auto PtrAuthSign = [&](llvm::Constant *C) { - if (auto pointerAuth = DestType.getPointerAuth()) { + if (auto PointerAuth = DestType.getPointerAuth()) { C = applyOffset(C); - C = Emitter.tryEmitConstantSignedPointer(C, pointerAuth); + C = Emitter.tryEmitConstantSignedPointer(C, PointerAuth); return ConstantLValue(C, /*applied offset*/ true, /*signed*/ true); } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 05c76cf85581c..be2338a1df67d 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2203,15 +2203,15 @@ static bool isDeclRefKnownNonNull(CodeGenFunction &CGF, const ValueDecl *D) { static bool isLValueKnownNonNull(CodeGenFunction &CGF, const Expr *E) { E = E->IgnoreParens(); - if (auto UO = dyn_cast(E)) { + if (auto *UO = dyn_cast(E)) { if (UO->getOpcode() == UO_Deref) { return CGF.isPointerKnownNonNull(UO->getSubExpr()); } } - if (auto DRE = dyn_cast(E)) { + if (auto *DRE = dyn_cast(E)) { return isDeclRefKnownNonNull(CGF, DRE->getDecl()); - } else if (auto ME = dyn_cast(E)) { + } else if (auto *ME = dyn_cast(E)) { if (isa(ME->getMemberDecl())) return true; return isDeclRefKnownNonNull(CGF, ME->getMemberDecl()); @@ -2230,13 +2230,13 @@ bool CodeGenFunction::isPointerKnownNonNull(const Expr *E) { if (isa(E)) return true; - if (auto UO = dyn_cast(E)) { + if (auto *UO = dyn_cast(E)) { if (UO->getOpcode() == UO_AddrOf) { return isLValueKnownNonNull(*this, UO->getSubExpr()); } } - if (auto CE = dyn_cast(E)) { + if (auto *CE = dyn_cast(E)) { if (CE->getCastKind() == CK_FunctionToPointerDecay || CE->getCastKind() == CK_ArrayToPointerDecay) { return isLValueKnownNonNull(*this, CE->getSubExpr()); @@ -4850,17 +4850,17 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { Value *RHS; LValue LHS; - if (auto ptrauth = E->getLHS()->getType().getPointerAuth()) { + if (auto PtrAuth = E->getLHS()->getType().getPointerAuth()) { LValue LV = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); LV.getQuals().removePointerAuth(); llvm::Value *RV = - CGF.EmitPointerAuthQualify(ptrauth, E->getRHS(), LV.getAddress()); + CGF.EmitPointerAuthQualify(PtrAuth, E->getRHS(), LV.getAddress()); CGF.EmitNullabilityCheck(LV, RV, E->getExprLoc()); CGF.EmitStoreThroughLValue(RValue::get(RV), LV); if (Ignore) return nullptr; - RV = CGF.EmitPointerAuthUnqualify(ptrauth, RV, LV.getType(), + RV = CGF.EmitPointerAuthUnqualify(PtrAuth, RV, LV.getType(), LV.getAddress(), /*nonnull*/ false); return RV; } diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 5cd9cba6b41d1..eec46eeab1f45 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -194,16 +194,16 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) { } static std::pair -emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &lv, - SourceLocation loc) { - auto value = CGF.EmitLoadOfScalar(lv, loc); - CGPointerAuthInfo authInfo; - if (auto ptrauth = lv.getQuals().getPointerAuth()) { - authInfo = CGF.EmitPointerAuthInfo(ptrauth, lv.getAddress()); +emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV, + SourceLocation Loc) { + auto *Value = CGF.EmitLoadOfScalar(LV, Loc); + CGPointerAuthInfo AuthInfo; + if (auto PtrAuth = LV.getQuals().getPointerAuth()) { + AuthInfo = CGF.EmitPointerAuthInfo(PtrAuth, LV.getAddress()); } else { - authInfo = getPointerAuthInfoForType(CGF.CGM, lv.getType()); + AuthInfo = getPointerAuthInfoForType(CGF.CGM, LV.getType()); } - return {value, authInfo}; + return {Value, AuthInfo}; } std::pair @@ -211,82 +211,82 @@ CodeGenFunction::EmitOrigPointerRValue(const Expr *E) { assert(E->getType()->isSignableType()); E = E->IgnoreParens(); - if (auto load = dyn_cast(E)) { - if (load->getCastKind() == CK_LValueToRValue) { - E = load->getSubExpr()->IgnoreParens(); + if (auto *Load = dyn_cast(E)) { + if (Load->getCastKind() == CK_LValueToRValue) { + E = Load->getSubExpr()->IgnoreParens(); // We're semantically required to not emit loads of certain DREs naively. - if (auto refExpr = dyn_cast(const_cast(E))) { - if (auto result = tryEmitAsConstant(refExpr)) { + if (auto *RefExpr = dyn_cast(const_cast(E))) { + if (auto Result = tryEmitAsConstant(RefExpr)) { // Fold away a use of an intermediate variable. - if (!result.isReference()) - return {result.getValue(), - getPointerAuthInfoForType(CGM, refExpr->getType())}; + if (!Result.isReference()) + return {Result.getValue(), + getPointerAuthInfoForType(CGM, RefExpr->getType())}; // Fold away a use of an intermediate reference. - auto lv = result.getReferenceLValue(*this, refExpr); - return emitLoadOfOrigPointerRValue(*this, lv, refExpr->getLocation()); + auto LV = Result.getReferenceLValue(*this, RefExpr); + return emitLoadOfOrigPointerRValue(*this, LV, RefExpr->getLocation()); } } // Otherwise, load and use the pointer - auto lv = EmitCheckedLValue(E, CodeGenFunction::TCK_Load); - return emitLoadOfOrigPointerRValue(*this, lv, E->getExprLoc()); + auto LV = EmitCheckedLValue(E, CodeGenFunction::TCK_Load); + return emitLoadOfOrigPointerRValue(*this, LV, E->getExprLoc()); } } // Emit direct references to functions without authentication. - if (auto DRE = dyn_cast(E)) { - if (auto FD = dyn_cast(DRE->getDecl())) { + if (auto *DRE = dyn_cast(E)) { + if (auto *FD = dyn_cast(DRE->getDecl())) { return {CGM.getRawFunctionPointer(FD), CGPointerAuthInfo()}; } - } else if (auto ME = dyn_cast(E)) { - if (auto FD = dyn_cast(ME->getMemberDecl())) { + } else if (auto *ME = dyn_cast(E)) { + if (auto *FD = dyn_cast(ME->getMemberDecl())) { EmitIgnoredExpr(ME->getBase()); return {CGM.getRawFunctionPointer(FD), CGPointerAuthInfo()}; } } // Fallback: just use the normal rules for the type. - auto value = EmitScalarExpr(E); - return {value, getPointerAuthInfoForType(CGM, E->getType())}; + auto *Value = EmitScalarExpr(E); + return {Value, getPointerAuthInfoForType(CGM, E->getType())}; } llvm::Value * -CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier destQualifier, +CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier DestQualifier, const Expr *E, - Address destStorageAddress) { - assert(destQualifier); + Address DestStorageAddress) { + assert(DestQualifier); - auto src = EmitOrigPointerRValue(E); - auto value = src.first; - auto curAuthInfo = src.second; + auto Src = EmitOrigPointerRValue(E); + auto *Value = Src.first; + auto CurAuthInfo = Src.second; - auto destAuthInfo = EmitPointerAuthInfo(destQualifier, destStorageAddress); - return emitPointerAuthResign(value, E->getType(), curAuthInfo, destAuthInfo, + auto DestAuthInfo = EmitPointerAuthInfo(DestQualifier, DestStorageAddress); + return emitPointerAuthResign(Value, E->getType(), CurAuthInfo, DestAuthInfo, isPointerKnownNonNull(E)); } llvm::Value *CodeGenFunction::EmitPointerAuthQualify( - PointerAuthQualifier destQualifier, llvm::Value *value, - QualType pointerType, Address destStorageAddress, bool isKnownNonNull) { - assert(destQualifier); + PointerAuthQualifier DestQualifier, llvm::Value *Value, + QualType PointerType, Address DestStorageAddress, bool IsKnownNonNull) { + assert(DestQualifier); - auto curAuthInfo = getPointerAuthInfoForType(CGM, pointerType); - auto destAuthInfo = EmitPointerAuthInfo(destQualifier, destStorageAddress); - return emitPointerAuthResign(value, pointerType, curAuthInfo, destAuthInfo, - isKnownNonNull); + auto CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType); + auto DestAuthInfo = EmitPointerAuthInfo(DestQualifier, DestStorageAddress); + return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo, + IsKnownNonNull); } llvm::Value *CodeGenFunction::EmitPointerAuthUnqualify( - PointerAuthQualifier curQualifier, llvm::Value *value, QualType pointerType, - Address curStorageAddress, bool isKnownNonNull) { - assert(curQualifier); - - auto curAuthInfo = EmitPointerAuthInfo(curQualifier, curStorageAddress); - auto destAuthInfo = getPointerAuthInfoForType(CGM, pointerType); - return emitPointerAuthResign(value, pointerType, curAuthInfo, destAuthInfo, - isKnownNonNull); + PointerAuthQualifier CurQualifier, llvm::Value *Value, QualType PointerType, + Address CurStorageAddress, bool IsKnownNonNull) { + assert(CurQualifier); + + auto CurAuthInfo = EmitPointerAuthInfo(CurQualifier, CurStorageAddress); + auto DestAuthInfo = getPointerAuthInfoForType(CGM, PointerType); + return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo, + IsKnownNonNull); } static bool isZeroConstant(const llvm::Value *Value) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e7729207cc6a6..91bfe551268f3 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4457,22 +4457,22 @@ class CodeGenFunction : public CodeGenTypeCache { const CGPointerAuthInfo &Info, SmallVectorImpl &Bundles); - CGPointerAuthInfo EmitPointerAuthInfo(PointerAuthQualifier qualifier, - Address storageAddress); - llvm::Value *EmitPointerAuthQualify(PointerAuthQualifier qualifier, - llvm::Value *pointer, QualType valueType, - Address storageAddress, - bool isKnownNonNull); - llvm::Value *EmitPointerAuthQualify(PointerAuthQualifier qualifier, - const Expr *pointerExpr, - Address storageAddress); - llvm::Value *EmitPointerAuthUnqualify(PointerAuthQualifier qualifier, - llvm::Value *pointer, - QualType pointerType, - Address storageAddress, - bool isKnownNonNull); - void EmitPointerAuthCopy(PointerAuthQualifier qualifier, QualType type, - Address destField, Address srcField); + CGPointerAuthInfo EmitPointerAuthInfo(PointerAuthQualifier Qualifier, + Address StorageAddress); + llvm::Value *EmitPointerAuthQualify(PointerAuthQualifier Qualifier, + llvm::Value *Pointer, QualType ValueType, + Address StorageAddress, + bool IsKnownNonNull); + llvm::Value *EmitPointerAuthQualify(PointerAuthQualifier Qualifier, + const Expr *PointerExpr, + Address StorageAddress); + llvm::Value *EmitPointerAuthUnqualify(PointerAuthQualifier Qualifier, + llvm::Value *Pointer, + QualType PointerType, + Address StorageAddress, + bool IsKnownNonNull); + void EmitPointerAuthCopy(PointerAuthQualifier Qualifier, QualType Type, + Address DestField, Address SrcField); std::pair EmitOrigPointerRValue(const Expr *E); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 2a14a6a34eede..1b0b63dc9f200 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3373,29 +3373,29 @@ void Parser::DistributeCLateParsedAttrs(Decl *Dcl, void Parser::ParsePtrauthQualifier(ParsedAttributes &attrs) { assert(Tok.is(tok::kw___ptrauth)); - IdentifierInfo *kwName = Tok.getIdentifierInfo(); - SourceLocation kwLoc = ConsumeToken(); + IdentifierInfo *KwName = Tok.getIdentifierInfo(); + SourceLocation KwLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume()) return; - ArgsVector argExprs; + ArgsVector ArgExprs; do { - ExprResult expr = ParseAssignmentExpression(); - if (expr.isInvalid()) { + ExprResult ER = ParseAssignmentExpression(); + if (ER.isInvalid()) { T.skipToEnd(); return; } - argExprs.push_back(expr.get()); + ArgExprs.push_back(ER.get()); } while (TryConsumeToken(tok::comma)); T.consumeClose(); - SourceLocation endLoc = T.getCloseLocation(); + SourceLocation EndLoc = T.getCloseLocation(); - attrs.addNew(kwName, SourceRange(kwLoc, endLoc), - /*scope*/ nullptr, SourceLocation(), argExprs.data(), - argExprs.size(), + attrs.addNew(KwName, SourceRange(KwLoc, EndLoc), + /*scope*/ nullptr, SourceLocation(), ArgExprs.data(), + ArgExprs.size(), ParsedAttr::Form::Keyword(/*IsAlignAs=*/false, /*IsRegularKeywordAttribute=*/false)); } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4aefc12789c13..c2d8e03285715 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1540,51 +1540,51 @@ bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) { return false; } -bool Sema::checkPointerAuthDiscriminatorArg(Expr *arg, - PointerAuthDiscArgKind kind, - unsigned &intVal) { - if (!arg) { - intVal = 0; +bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg, + PointerAuthDiscArgKind Kind, + unsigned &IntVal) { + if (!Arg) { + IntVal = 0; return true; } - std::optional result = arg->getIntegerConstantExpr(Context); - if (!result) { - Diag(arg->getExprLoc(), diag::err_ptrauth_arg_not_ice); + std::optional Result = Arg->getIntegerConstantExpr(Context); + if (!Result) { + Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice); return false; } - unsigned max; - bool isAddrDiscArg = false; + unsigned Max; + bool IsAddrDiscArg = false; - switch (kind) { + switch (Kind) { case PADAK_AddrDiscPtrAuth: - max = 1; - isAddrDiscArg = true; + Max = 1; + IsAddrDiscArg = true; break; case PADAK_ExtraDiscPtrAuth: - max = PointerAuthQualifier::MaxDiscriminator; + Max = PointerAuthQualifier::MaxDiscriminator; break; }; - if (*result < 0 || *result > max) { - llvm::SmallString<32> value; + if (*Result < 0 || *Result > Max) { + llvm::SmallString<32> Value; { - llvm::raw_svector_ostream str(value); - str << *result; + llvm::raw_svector_ostream str(Value); + str << *Result; } - if (isAddrDiscArg) - Diag(arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid) - << value; + if (IsAddrDiscArg) + Diag(Arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid) + << Value; else - Diag(arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid) - << value << max; + Diag(Arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid) + << Value << Max; return false; }; - intVal = result->getZExtValue(); + IntVal = Result->getZExtValue(); return true; } @@ -4217,8 +4217,8 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { << FirstArg->getType() << 0 << FirstArg->getSourceRange(); return ExprError(); } - auto pointerAuth = ValType.getPointerAuth(); - if (pointerAuth && pointerAuth.isAddressDiscriminated()) { + auto PointerAuth = ValType.getPointerAuth(); + if (PointerAuth && PointerAuth.isAddressDiscriminated()) { Diag(FirstArg->getBeginLoc(), diag::err_atomic_op_needs_non_address_discriminated_pointer) << 1 << ValType << FirstArg->getSourceRange(); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index c4da0f237c833..515f874639509 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8229,51 +8229,51 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, } /// Handle the __ptrauth qualifier. -static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &type, +static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, const ParsedAttr &attr, Sema &S) { - auto attributeName = attr.getAttrName()->getName(); + auto AttributeName = attr.getAttrName()->getName(); if (attr.getNumArgs() < 1 || attr.getNumArgs() > 3) { S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_bad_arg_count) - << attributeName; + << AttributeName; attr.setInvalid(); return; } - Expr *keyArg = attr.getArgAsExpr(0); - Expr *isAddressDiscriminatedArg = + Expr *KeyArg = attr.getArgAsExpr(0); + Expr *IsAddressDiscriminatedArg = attr.getNumArgs() >= 2 ? attr.getArgAsExpr(1) : nullptr; - Expr *extraDiscriminatorArg = + Expr *ExtraDiscriminatorArg = attr.getNumArgs() >= 3 ? attr.getArgAsExpr(2) : nullptr; - unsigned key; - if (S.checkConstantPointerAuthKey(keyArg, key)) { + unsigned Key; + if (S.checkConstantPointerAuthKey(KeyArg, Key)) { attr.setInvalid(); return; } - assert(key <= PointerAuthQualifier::MaxKey && "ptrauth key is out of range"); + assert(Key <= PointerAuthQualifier::MaxKey && "ptrauth key is out of range"); - bool isInvalid = false; - unsigned isAddressDiscriminated, extraDiscriminator; - isInvalid |= !S.checkPointerAuthDiscriminatorArg(isAddressDiscriminatedArg, + bool IsInvalid = false; + unsigned IsAddressDiscriminated, ExtraDiscriminator; + IsInvalid |= !S.checkPointerAuthDiscriminatorArg(IsAddressDiscriminatedArg, Sema::PADAK_AddrDiscPtrAuth, - isAddressDiscriminated); - isInvalid |= !S.checkPointerAuthDiscriminatorArg( - extraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, extraDiscriminator); + IsAddressDiscriminated); + IsInvalid |= !S.checkPointerAuthDiscriminatorArg( + ExtraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, ExtraDiscriminator); - if (isInvalid) { + if (IsInvalid) { attr.setInvalid(); return; } - if (!type->isSignableType() && !type->isDependentType()) { - S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << type; + if (!T->isSignableType() && !T->isDependentType()) { + S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T; attr.setInvalid(); return; } - if (type.getPointerAuth()) { + if (T.getPointerAuth()) { S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_redundant) - << type << attr.getAttrName()->getName(); + << T << attr.getAttrName()->getName(); attr.setInvalid(); return; } @@ -8284,12 +8284,12 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &type, return; } - assert((!isAddressDiscriminatedArg || isAddressDiscriminated <= 1) && + assert((!IsAddressDiscriminatedArg || IsAddressDiscriminated <= 1) && "address discriminator arg should be either 0 or 1"); - PointerAuthQualifier qual = PointerAuthQualifier::Create( - key, isAddressDiscriminated, extraDiscriminator, + PointerAuthQualifier Qual = PointerAuthQualifier::Create( + Key, IsAddressDiscriminated, ExtraDiscriminator, PointerAuthenticationMode::SignAndAuth, false, false); - type = S.Context.getPointerAuthType(type, qual); + T = S.Context.getPointerAuthType(T, Qual); } /// HandleArmSveVectorBitsTypeAttr - The "arm_sve_vector_bits" attribute is From 66c1f79e9a9dd4a1c521ddc5956e533ecba77c36 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 26 Jul 2024 17:14:01 -0700 Subject: [PATCH 03/19] Revert unnecessary change --- clang/lib/CodeGen/CGExprConstant.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 9cc80c4385d29..8f3266dfbd094 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2352,9 +2352,6 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, QualType DestType, EnablePtrAuthFunctionTypeDiscrimination) .tryEmit(); case APValue::Int: - if (DestType.getPointerAuth() && Value.getInt() != 0) { - return nullptr; - } return llvm::ConstantInt::get(CGM.getLLVMContext(), Value.getInt()); case APValue::FixedPoint: return llvm::ConstantInt::get(CGM.getLLVMContext(), From 73a242284699fa1f5fd491843eb85986a971a401 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 29 Jul 2024 22:22:32 -0700 Subject: [PATCH 04/19] Fix coding style violations Improve docs and comments. Add a test for the type printer. --- clang/docs/PointerAuthentication.rst | 46 +++++++ clang/include/clang/AST/Type.h | 2 +- clang/include/clang/Basic/AttrDocs.td | 122 +----------------- clang/lib/AST/ItaniumMangle.cpp | 2 +- clang/lib/AST/TypePrinter.cpp | 4 +- clang/lib/CodeGen/CGDebugInfo.cpp | 6 +- clang/lib/CodeGen/CGDecl.cpp | 2 +- clang/lib/CodeGen/CGExpr.cpp | 7 +- clang/lib/CodeGen/CGExprConstant.cpp | 4 +- clang/lib/CodeGen/CGExprScalar.cpp | 2 +- clang/lib/CodeGen/CGPointerAuth.cpp | 16 +-- clang/lib/Sema/SemaChecking.cpp | 4 +- clang/test/AST/ast-dump-ptrauth-json.cpp | 2 + clang/test/Preprocessor/ptrauth_feature.c | 2 - ...mic-ops-ptrauth.c => ptrauth-atomic-ops.c} | 0 15 files changed, 70 insertions(+), 151 deletions(-) rename clang/test/Sema/{atomic-ops-ptrauth.c => ptrauth-atomic-ops.c} (100%) diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst index 68674f318c84f..41818d43ac687 100644 --- a/clang/docs/PointerAuthentication.rst +++ b/clang/docs/PointerAuthentication.rst @@ -280,6 +280,52 @@ a number of different tests. normal interface. This may be true even on targets where pointer authentication is not enabled by default. +__ptrauth Qualifier +^^^^^^^^^^^^^^^^^^^ + +``__ptrauth(key, address, discriminator)`` is an extended type +qualifier which causes so-qualified objects to hold pointers signed using the +specified schema rather than the default schema for such types. + +In the current implementation in Clang, the qualified type must be a C pointer +type, either to a function or to an object. It currently cannot be an +Objective-C pointer type, a C++ reference type, or a block pointer type; these +restrictions may be lifted in the future. + +The qualifier's operands are as follows: + +- ``key`` - an expression evaluating to a key value from ````; must + be a constant expression + +- ``address`` - whether to use address diversity (1) or not (0); must be + a constant expression with one of these two values + +- ``discriminator`` - a constant discriminator; must be a constant expression + +See `Discriminators`_ for more information about discriminators. + +Currently the operands must be constant-evaluable even within templates. In the +future this restriction may be lifted to allow value-dependent expressions as +long as they instantiate to a constant expression. + +Consistent with the ordinary C/C++ rule for parameters, top-level ``__ptrauth`` +qualifiers on a parameter (after parameter type adjustment) are ignored when +deriving the type of the function. The parameter will be passed using the +default ABI for the unqualified pointer type. + +If ``x`` is an object of type ``__ptrauth(key, address, discriminator) T``, +then the signing schema of the value stored in ``x`` is a key of ``key`` and +a discriminator determined as follows: + +- if ``address`` is 0, then the discriminator is ``discriminator``; + +- if ``address`` is 1 and ``discriminator`` is 0, then the discriminator is + ``&x``; otherwise + +- if ``address`` is 1 and ``discriminator`` is non-zero, then the discriminator + is ``ptrauth_blend_discriminator(&x, discriminator)``; see + `ptrauth_blend_discriminator`_. + ```` ~~~~~~~~~~~~~~~ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index b84d808410583..2fb17f352f1b3 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1468,7 +1468,7 @@ class QualType { } bool hasAddressDiscriminatedPointerAuth() const { - if (auto ptrauth = getPointerAuth()) + if (PointerAuthQualifier ptrauth = getPointerAuth()) return ptrauth.isAddressDiscriminated(); return false; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 547cb010ebc84..e7b990a2abb8c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1778,129 +1778,11 @@ an ability to alter memory into full control of a process. The first argument to ``__ptrauth`` is the name of the signing key. Valid key names for the target are defined in ````. -On ARM64, there are four keys: - -- ``ptrauth_key_process_independent_data`` -- ``ptrauth_key_process_dependent_data`` -- ``ptrauth_key_process_independent_code`` -- ``ptrauth_key_process_dependent_code`` - -In general, prefer using a code key for function pointers and a data key -for object pointers. The ARM64 architecture allows loads and calls to -execute more efficiently when the pointer is signed with an appropriate -key. Using code keys only for function pointers also substantially lessens -the risk of creating a so-called "signing oracle" for function pointers; -see the general pointer authentication language documentation. - -Using a process-dependent key provides stronger protection against -cross-process attacks. However, it also inhibits certain memory -optimizations when a shared library is loaded into multiple processes. -Using a process-independent key also allows signed pointers to be passed -in shared memory. Note that even the process-independent keys may change -after a reboot, so signed values should never be serialized. - The second argument to ``__ptrauth`` is a flag (0 or 1) specifying whether -the object should use address discrimination. If only one argument is -given, the flag defaults to 0. Address discrimination provides strong -protection against attacks which copy signed pointers around in memory. -An attacker cannot usefully copy an arbitrary signed pointer over an -address-discriminated object. Nor can a value taken from an -address-discriminated object be usefully copied over some other signed -pointer. However, it is more expensive to copy values from one -address-discriminated object to another, even if the other arguments to -``__ptrauth`` are the same, and it is not valid to copy them with -``memcpy``. It is also not valid to map memory containing an -address-discriminated object into different places in the address -space, e.g. with ``mmap``. +the object should use address discrimination. The third argument to ``__ptrauth`` is a small non-negative integer -which allows additional discrimination between objects. Using a -unique extra discriminator provides strong protection against attacks -which work by substituting one signed value for another. For example, -an attacker cannot usefully overwrite an object with a pointer from an -object using a different extra discriminator; this protection is similar -to the protection offered by address discrimination. A unique extra -discriminator also protects against "slide" attacks where an attacker -alters a pointer instead of altering the memory that the pointer points to. -The extra discriminator must be a constant expression. On ARM64, -its value must be between 0 and 65535. If the argument is not provided, -the default value is 0. It is generally preferable not to use the value 0, -especially with the process-independent keys, as this combination is used -in various places in the standard language ABI. - -The type qualified by ``__ptrauth`` must be a pointer type. Currently -only C pointer types are allowed and not block pointers, Objective-C -object pointers, or C++ references. ``__ptrauth`` is parsed and interpreted -using the same language rules as qualifiers like ``const`` and ``volatile``. -For example: - -.. code-block:: c - - __ptrauth(...) int *ex0; /* invalid: qualifies 'int', which is not a pointer type */ - int * __ptrauth(...) ex1; /* valid: ex1 has qualified type */ - int * __ptrauth(...) *ex2; /* valid: ex2 is a pointer to a qualified object */ - - typedef int *intp; - __ptrauth(...) intp ex3; /* valid: ex3 has qualified type */ - intp __ptrauth(...) ex4; /* valid: means the exact same thing as ex3 */ - -If a ``__ptrauth``-qualified l-value of function pointer type is -used as the function operand of a call expression, the function pointer -will be authenticated "atomically" with the call, such that an attacker -will not be able to corrupt the destination of the call even in the -presence of undefined behavior. (That is, the compiler must not -leave an un-signed pointer that it will later unconditionally trust -in a place where it could be feasibly overwritten by an attacker, -such as the stack or a callee-save register during an intervening call. -The compiler is not required to protect against improbable attacks -such as corruption of the register file, as might occur with a -corrupted kernel. It also need not guard against jumps to an arbitrary -place in the instruction stream, since such jumps would require an -attacker to already fully control the PC.) - -If the ABI specifies that a pointer is always signed --- that is, -if the pointer is a function pointer and the target uses ABI function -pointer authentication --- then signing and authenticating it as part -of a load/store actually means resigning it to/from the standard ABI -signature schema. Similarly, if both operands of a simple assignment -operator are ``__ptrauth``-qualified, the pointer copied by the -assignment is resigned from the right-hand operand's schema to the -left-hand operand's schema. These resigning operations are also done -"atomically" in the same sense as above. - -As a final guarantee, if the right-hand operand of an assignment or -the expression used to initialize a ``__ptrauth``-qualified object is -a direct reference to an object or function (e.g. ``&my_var``), the -signing of that pointer is atomic with the evaluaton of the reference -in this same sense. - -Otherwise, there are no guarantees of atomicity, and it is the -programmer's responsibility to avoid allowing a store into a -``__ptrauth``-qualified object to create a potential "signing oracle" -which an attacker could use to sign an arbitrary pointer of their choice. -Such oracles are particularly problematic when the signing uses a code -key because the oracle could potentially be used to allow an attacker -to construct a validly-signed function pointer, v-table entry, or -return address that points to an arbitrary instruction, allowing them -to completely take over the PC. Programmers attempting to use -``__ptrauth`` to protect a data pointer, or to protect function pointers -on targets that do not use ABI function pointer authentication, should -aim to maintain a "chain of authentication" from initialization all -the way to the point at which the pointer is used. If this is infeasible, -they should consider using ``ptrauth_sign_generic_data`` instead. - -Types that are written in r-value positions, such as return types, -parameter types, and cast types, may not be ``__ptrauth``-qualified -at the outermost level. This may be supported in the future. - -In C++, the arguments to ``__ptrauth`` may not be instantiation-dependent. -This may be supported in the future. - -This feature may be tested for with ``__has_feature(ptrauth_qualifier)``. -It is enabled whenever the ``ptrauth`` intrinsics are enabled. - -```` provides predefined qualifiers for various language -features that implicitly use pointer authentication. +which allows additional discrimination between objects. }]; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index c6c92fb780c18..0e95517bfa424 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2823,7 +2823,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp mangleVendorQualifier("__unaligned"); // __ptrauth. Note that this is parameterized. - if (auto PtrAuth = Quals.getPointerAuth()) { + if (PointerAuthQualifier PtrAuth = Quals.getPointerAuth()) { mangleVendorQualifier("__ptrauth"); // For now, since we only allow non-dependent arguments, we can just // inline the mangling of those arguments as literals. We treat the diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 3598936cd042f..542cf7502e20e 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -2470,7 +2470,7 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)) return false; - if (auto PointerAuth = getPointerAuth()) + if (PointerAuthQualifier PointerAuth = getPointerAuth()) if (!PointerAuth.isEmptyWhenPrinted(Policy)) return false; @@ -2580,7 +2580,7 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, } } - if (auto PointerAuth = getPointerAuth()) { + if (PointerAuthQualifier PointerAuth = getPointerAuth()) { if (addSpace) OS << ' '; addSpace = true; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index ae4026a84601e..fe4106adf56ee 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1025,9 +1025,9 @@ llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, Qc.removePointerAuth(); assert(Qc.empty() && "Unknown type qualifier for debug info"); auto *FromTy = getOrCreateType(QualType(T, 0), Unit); - return DBuilder.createPtrAuthQualifiedType( - FromTy, Key, IsDiscr, ExtraDiscr, /*IsaPointer=*/IsaPointer, - /*AuthenticatesNullValues=*/AuthenticatesNullValues); + return DBuilder.createPtrAuthQualifiedType(FromTy, Key, IsDiscr, + ExtraDiscr, IsaPointer, + AuthenticatesNullValues); } else { assert(Qc.empty() && "Unknown type qualifier for debug info"); return getOrCreateType(QualType(T, 0), Unit); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index c81ad78425c03..ef612300b4648 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -796,7 +796,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime(); if (!lifetime) { llvm::Value *Value; - if (auto PtrAuth = lvalue.getQuals().getPointerAuth()) { + if (PointerAuthQualifier PtrAuth = lvalue.getQuals().getPointerAuth()) { Value = EmitPointerAuthQualify(PtrAuth, init, lvalue.getAddress()); lvalue.getQuals().removePointerAuth(); } else { diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 0d43f824e489e..20caf0211cec1 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2191,7 +2191,7 @@ RValue CodeGenFunction::EmitLoadOfAnyValue(LValue LV, AggValueSlot Slot, /// returning the rvalue. RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { // Load from __ptrauth. - if (auto PtrAuth = LV.getQuals().getPointerAuth()) { + if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth()) { LV.getQuals().removePointerAuth(); auto value = EmitLoadOfLValue(LV, Loc).getScalarVal(); return RValue::get(EmitPointerAuthUnqualify(PtrAuth, value, LV.getType(), @@ -2427,7 +2427,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, } // Handle __ptrauth qualification by re-signing the value. - if (auto PointerAuth = Dst.getQuals().getPointerAuth()) { + if (PointerAuthQualifier PointerAuth = Dst.getQuals().getPointerAuth()) { Src = RValue::get(EmitPointerAuthQualify(PointerAuth, Src.getScalarVal(), Dst.getType(), Dst.getAddress(), /*known nonnull*/ false)); @@ -5654,7 +5654,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { switch (getEvaluationKind(E->getType())) { case TEK_Scalar: { - if (auto PtrAuth = E->getLHS()->getType().getPointerAuth()) { + if (PointerAuthQualifier PtrAuth = + E->getLHS()->getType().getPointerAuth()) { LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); LValue CopiedLV = LV; CopiedLV.getQuals().removePointerAuth(); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 8f3266dfbd094..1aaf81cc41cad 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2068,7 +2068,7 @@ llvm::Constant *ConstantLValueEmitter::tryEmit() { } // Apply pointer-auth signing from the destination type. - if (auto PointerAuth = DestType.getPointerAuth()) { + if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth()) { if (!result.HasDestPointerAuth) { value = Emitter.tryEmitConstantSignedPointer(value, PointerAuth); if (!value) @@ -2119,7 +2119,7 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { return CGM.GetWeakRefReference(D).getPointer(); auto PtrAuthSign = [&](llvm::Constant *C) { - if (auto PointerAuth = DestType.getPointerAuth()) { + if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth()) { C = applyOffset(C); C = Emitter.tryEmitConstantSignedPointer(C, PointerAuth); return ConstantLValue(C, /*applied offset*/ true, /*signed*/ true); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index be2338a1df67d..0047ee4dca6fa 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -4850,7 +4850,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { Value *RHS; LValue LHS; - if (auto PtrAuth = E->getLHS()->getType().getPointerAuth()) { + if (PointerAuthQualifier PtrAuth = E->getLHS()->getType().getPointerAuth()) { LValue LV = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); LV.getQuals().removePointerAuth(); llvm::Value *RV = diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index eec46eeab1f45..a2a014edbba12 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -198,7 +198,7 @@ emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV, SourceLocation Loc) { auto *Value = CGF.EmitLoadOfScalar(LV, Loc); CGPointerAuthInfo AuthInfo; - if (auto PtrAuth = LV.getQuals().getPointerAuth()) { + if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth()) { AuthInfo = CGF.EmitPointerAuthInfo(PtrAuth, LV.getAddress()); } else { AuthInfo = getPointerAuthInfoForType(CGF.CGM, LV.getType()); @@ -206,6 +206,8 @@ emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV, return {Value, AuthInfo}; } +/// Retrieve a pointer rvalue and its ptrauth info. When possible, avoid +/// needlessly resigning the pointer. std::pair CodeGenFunction::EmitOrigPointerRValue(const Expr *E) { assert(E->getType()->isSignableType()); @@ -235,18 +237,6 @@ CodeGenFunction::EmitOrigPointerRValue(const Expr *E) { } } - // Emit direct references to functions without authentication. - if (auto *DRE = dyn_cast(E)) { - if (auto *FD = dyn_cast(DRE->getDecl())) { - return {CGM.getRawFunctionPointer(FD), CGPointerAuthInfo()}; - } - } else if (auto *ME = dyn_cast(E)) { - if (auto *FD = dyn_cast(ME->getMemberDecl())) { - EmitIgnoredExpr(ME->getBase()); - return {CGM.getRawFunctionPointer(FD), CGPointerAuthInfo()}; - } - } - // Fallback: just use the normal rules for the type. auto *Value = EmitScalarExpr(E); return {Value, getPointerAuthInfoForType(CGM, E->getType())}; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index c2d8e03285715..f7d6c318924bb 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3843,7 +3843,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, return ExprError(); } - auto PointerAuth = AtomTy.getPointerAuth(); + PointerAuthQualifier PointerAuth = AtomTy.getPointerAuth(); if (PointerAuth && PointerAuth.isAddressDiscriminated()) { Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_address_discriminated_pointer) @@ -4217,7 +4217,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { << FirstArg->getType() << 0 << FirstArg->getSourceRange(); return ExprError(); } - auto PointerAuth = ValType.getPointerAuth(); + PointerAuthQualifier PointerAuth = ValType.getPointerAuth(); if (PointerAuth && PointerAuth.isAddressDiscriminated()) { Diag(FirstArg->getBeginLoc(), diag::err_atomic_op_needs_non_address_discriminated_pointer) diff --git a/clang/test/AST/ast-dump-ptrauth-json.cpp b/clang/test/AST/ast-dump-ptrauth-json.cpp index 125cda0cff53a..a85b1d8557335 100644 --- a/clang/test/AST/ast-dump-ptrauth-json.cpp +++ b/clang/test/AST/ast-dump-ptrauth-json.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -std=c++11 -ast-dump=json %s | FileCheck %s // CHECK: "name": "__builtin_ptrauth_type_discriminator", +// CHECK: "qualType": "int *__ptrauth(1,1,123)" int d = __builtin_ptrauth_type_discriminator(int()); +int * __ptrauth(1,1,123) p; diff --git a/clang/test/Preprocessor/ptrauth_feature.c b/clang/test/Preprocessor/ptrauth_feature.c index 14ef80860d0e9..397f10aa7ab3f 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -85,8 +85,6 @@ void has_ptrauth_type_info_vtable_pointer_discrimination() {} void no_ptrauth_type_info_vtable_pointer_discrimination() {} #endif -#include - #if __has_feature(ptrauth_function_pointer_type_discrimination) // FUNC: has_ptrauth_function_pointer_type_discrimination void has_ptrauth_function_pointer_type_discrimination() {} diff --git a/clang/test/Sema/atomic-ops-ptrauth.c b/clang/test/Sema/ptrauth-atomic-ops.c similarity index 100% rename from clang/test/Sema/atomic-ops-ptrauth.c rename to clang/test/Sema/ptrauth-atomic-ops.c From f0983226b5eff012c334b8a0b2989966a60101cd Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Thu, 1 Aug 2024 11:33:52 -0700 Subject: [PATCH 05/19] Strip qualifiers when evaluating a reference as an rvalue --- clang/lib/CodeGen/CGExpr.cpp | 2 +- .../test/CodeGen/ptrauth-qualifier-function.c | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 20caf0211cec1..583da32f7626a 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1750,7 +1750,7 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { if (CEK != CEK_AsReferenceOnly && refExpr->EvaluateAsRValue(result, getContext())) { resultIsReference = false; - resultType = refExpr->getType(); + resultType = refExpr->getType().getUnqualifiedType(); // Otherwise, try to evaluate as an l-value. } else if (CEK != CEK_AsValueOnly && diff --git a/clang/test/CodeGen/ptrauth-qualifier-function.c b/clang/test/CodeGen/ptrauth-qualifier-function.c index f6cde0cd96e62..6b5b2c707b5c4 100644 --- a/clang/test/CodeGen/ptrauth-qualifier-function.c +++ b/clang/test/CodeGen/ptrauth-qualifier-function.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s -// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s +// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,CHECK-CXX %s #ifdef __cplusplus extern "C" { @@ -7,6 +7,8 @@ extern "C" { void (*fptr)(void); void (* __ptrauth(0, 0, 42) f2ptr_42_discm)(int); +void f(int); +void (* const __ptrauth(0, 0, 42) f_const_ptr)(int) = &f; // CHECK-LABEL: define void @test_assign_to_qualified void test_assign_to_qualified() { @@ -70,6 +72,24 @@ void test_assign_from_qualified() { // CHECK-NEXT store void ()* [[FPTR10]], void ()** @f2ptr_42_discm } +// CHECK-LABEL: define void @test_const_ptr_function_call() +void test_const_ptr_function_call(void) { + f_const_ptr(1); + + // CHECK: call void ptrauth (ptr @f, i32 0, i64 2712)(i32 noundef 1) [ "ptrauth"(i32 0, i64 2712) ] +} + #ifdef __cplusplus +void (* get_fptr(void))(int); +void (* __ptrauth(0, 0, 42) f_const_ptr2)(int) = get_fptr(); +void (* const __ptrauth(0, 0, 42) &f_ref)(int) = f_const_ptr2; + +// CHECK-CXX-LABEL: define void @test_const_ptr_ref_function_call() +void test_const_ptr_ref_function_call(void) { + f_ref(1); + + // CHECK-CXX: %[[V0:.*]] = load ptr, ptr @f_const_ptr2, align 8 + // CHECK-CXX: call void %[[V0]](i32 noundef 1) [ "ptrauth"(i32 0, i64 42) ] +} } #endif From a7609231eb7d8b87902a6f785e656e2b187f80ff Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Thu, 1 Aug 2024 14:55:00 -0700 Subject: [PATCH 06/19] Resign pointer when materializing temporary --- clang/lib/CodeGen/CGExpr.cpp | 10 ++++- .../test/CodeGen/ptrauth-qualifier-function.c | 43 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 583da32f7626a..5a4d7f0fe55d4 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -527,7 +527,15 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { // initialized it. if (!Var->hasInitializer()) { Var->setInitializer(CGM.EmitNullConstant(E->getType())); - EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true); + QualType RefType = M->getType(); + if (RefType.getPointerAuth()) { + // Use the qualifier of the reference temporary to sign the pointer. + auto LV = MakeRawAddrLValue(Object.getPointer(), RefType, + Object.getAlignment()); + EmitScalarInit(E, M->getExtendingDecl(), LV, false); + } else { + EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/ true); + } } } else { switch (M->getStorageDuration()) { diff --git a/clang/test/CodeGen/ptrauth-qualifier-function.c b/clang/test/CodeGen/ptrauth-qualifier-function.c index 6b5b2c707b5c4..133c396dcb9d4 100644 --- a/clang/test/CodeGen/ptrauth-qualifier-function.c +++ b/clang/test/CodeGen/ptrauth-qualifier-function.c @@ -82,14 +82,51 @@ void test_const_ptr_function_call(void) { #ifdef __cplusplus void (* get_fptr(void))(int); void (* __ptrauth(0, 0, 42) f_const_ptr2)(int) = get_fptr(); -void (* const __ptrauth(0, 0, 42) &f_ref)(int) = f_const_ptr2; +void (* const __ptrauth(0, 1, 43) &f_ref)(int) = f_const_ptr2; + +// CHECK-CXX-LABEL: define internal void @__cxx_global_var_init() +// CHECK-CXX: [[ENTRY:.*]]: +// CHECK-CXX: %[[CALL:.*]] = call ptr @get_fptr() +// CHECK-CXX: %[[V0:.*]] = icmp ne ptr %[[CALL]], null +// CHECK-CXX: br i1 %[[V0]], label %[[RESIGN_NONNULL:.*]], label %[[RESIGN_CONT:.*]] + +// CHECK-CXX: [[RESIGN_NONNULL]]: +// CHECK-CXX: %[[V1:.*]] = ptrtoint ptr %[[CALL]] to i64 +// CHECK-CXX: %[[V2:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V1]], i32 0, i64 2712, i32 0, i64 42) +// CHECK-CXX: %[[V3:.*]] = inttoptr i64 %[[V2]] to ptr +// CHECK-CXX: br label %[[RESIGN_CONT]] + +// CHECK-CXX: [[RESIGN_CONT]]: +// CHECK-CXX: %[[V4:.*]] = phi ptr [ null, %[[ENTRY]] ], [ %[[V3]], %[[RESIGN_NONNULL]] ] +// CHECK-CXX: store ptr %[[V4]], ptr @f_const_ptr2, align 8 + +// CHECK-CXX-LABEL: define internal void @__cxx_global_var_init.1() +// CHECK-CXX: [[ENTRY:.*]]: +// CHECK-CXX: %[[V0:.*]] = load ptr, ptr @f_const_ptr2, align 8 +// CHECK-CXX: %[[V1:.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @_ZGR5f_ref_ to i64), i64 43) +// CHECK-CXX: %[[V2:.*]] = icmp ne ptr %[[V0]], null +// CHECK-CXX: br i1 %[[V2]], label %[[RESIGN_NONNULL:.*]], label %[[RESIGN_CONT:.*]] + +// CHECK-CXX: [[RESIGN_NONNULL]]: +// CHECK-CXX: %[[V3:.*]] = ptrtoint ptr %[[V0]] to i64 +// CHECK-CXX: %[[V4:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V3]], i32 0, i64 42, i32 0, i64 %[[V1]]) +// CHECK-CXX: %[[V5:.*]] = inttoptr i64 %[[V4]] to ptr +// CHECK-CXX: br label %[[RESIGN_CONT]] + +// CHECK-CXX: [[RESIGN_CONT]]: +// CHECK-CXX: %[[V6:.*]] = phi ptr [ null, %[[ENTRY]] ], [ %[[V5]], %[[RESIGN_NONNULL]] ] +// CHECK-CXX: store ptr %[[V6]], ptr @_ZGR5f_ref_, align 8 +// CHECK-CXX: store ptr @_ZGR5f_ref_, ptr @f_ref, align 8 // CHECK-CXX-LABEL: define void @test_const_ptr_ref_function_call() void test_const_ptr_ref_function_call(void) { f_ref(1); - // CHECK-CXX: %[[V0:.*]] = load ptr, ptr @f_const_ptr2, align 8 - // CHECK-CXX: call void %[[V0]](i32 noundef 1) [ "ptrauth"(i32 0, i64 42) ] + // CHECK-CXX: %[[V0:.*]] = load ptr, ptr @f_ref, align 8 + // CHECK-CXX: %[[V1:.*]] = load ptr, ptr %[[V0]], align 8 + // CHECK-CXX: %[[V2:.*]] = ptrtoint ptr %[[V0]] to i64 + // CHECK-CXX: %[[V3:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V2]], i64 43) + // CHECK-CXX: call void %[[V1]](i32 noundef 1) [ "ptrauth"(i32 0, i64 %[[V3]]) ] } } #endif From d64227df327e79d2fdb672844e4b32c589e9d7f5 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 5 Aug 2024 15:43:59 -0700 Subject: [PATCH 07/19] Address review comments --- clang/include/clang/AST/Type.h | 4 +- clang/include/clang/Basic/AttrDocs.td | 4 +- clang/lib/CodeGen/CGExpr.cpp | 40 +++++------ clang/lib/CodeGen/CGExprScalar.cpp | 23 +++---- clang/lib/CodeGen/CGPointerAuth.cpp | 9 ++- clang/lib/CodeGen/CodeGenFunction.h | 6 +- clang/lib/Sema/SemaType.cpp | 34 +++++----- clang/test/CodeGen/ptrauth-debuginfo.c | 4 +- ...ifier.c => ptrauth-qualifier-const-init.c} | 2 - .../test/CodeGen/ptrauth-qualifier-function.c | 68 +++++++++++-------- clang/test/Sema/ptrauth-qualifier.c | 5 +- .../SemaCXX/ptrauth-template-parameters.cpp | 2 +- 12 files changed, 102 insertions(+), 99 deletions(-) rename clang/test/CodeGen/{ptrauth-qualifier.c => ptrauth-qualifier-const-init.c} (99%) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 2fb17f352f1b3..c63bc9428bb5e 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1468,8 +1468,8 @@ class QualType { } bool hasAddressDiscriminatedPointerAuth() const { - if (PointerAuthQualifier ptrauth = getPointerAuth()) - return ptrauth.isAddressDiscriminated(); + if (PointerAuthQualifier PtrAuth = getPointerAuth()) + return PtrAuth.isAddressDiscriminated(); return false; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index e7b990a2abb8c..ce89802b8134d 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1781,8 +1781,8 @@ Valid key names for the target are defined in ````. The second argument to ``__ptrauth`` is a flag (0 or 1) specifying whether the object should use address discrimination. -The third argument to ``__ptrauth`` is a small non-negative integer -which allows additional discrimination between objects. +The third argument to ``__ptrauth`` is a 16-bit non-negative integer which +allows additional discrimination between objects. }]; } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 5a4d7f0fe55d4..eca578de3c0a7 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1734,16 +1734,16 @@ static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) { /// for instance if a block or lambda or a member of a local class uses a /// const int variable or constexpr variable from an enclosing function. CodeGenFunction::ConstantEmission -CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { - ValueDecl *value = refExpr->getDecl(); +CodeGenFunction::tryEmitAsConstant(const DeclRefExpr *RefExpr) { + const ValueDecl *Value = RefExpr->getDecl(); // The value needs to be an enum constant or a constant variable. ConstantEmissionKind CEK; - if (isa(value)) { + if (isa(Value)) { CEK = CEK_None; - } else if (auto *var = dyn_cast(value)) { + } else if (auto *var = dyn_cast(Value)) { CEK = checkVarTypeForConstantEmission(var->getType()); - } else if (isa(value)) { + } else if (isa(Value)) { CEK = CEK_AsValueOnly; } else { CEK = CEK_None; @@ -1756,15 +1756,15 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { // It's best to evaluate all the way as an r-value if that's permitted. if (CEK != CEK_AsReferenceOnly && - refExpr->EvaluateAsRValue(result, getContext())) { + RefExpr->EvaluateAsRValue(result, getContext())) { resultIsReference = false; - resultType = refExpr->getType().getUnqualifiedType(); + resultType = RefExpr->getType().getUnqualifiedType(); // Otherwise, try to evaluate as an l-value. } else if (CEK != CEK_AsValueOnly && - refExpr->EvaluateAsLValue(result, getContext())) { + RefExpr->EvaluateAsLValue(result, getContext())) { resultIsReference = true; - resultType = value->getType(); + resultType = Value->getType(); // Failure. } else { @@ -1783,7 +1783,7 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { // accessible on device. The DRE of the captured reference variable has to be // loaded from captures. if (CGM.getLangOpts().CUDAIsDevice && result.Val.isLValue() && - refExpr->refersToEnclosingVariableOrCapture()) { + RefExpr->refersToEnclosingVariableOrCapture()) { auto *MD = dyn_cast_or_null(CurCodeDecl); if (MD && MD->getParent()->isLambda() && MD->getOverloadedOperator() == OO_Call) { @@ -1799,17 +1799,17 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { } // Emit as a constant. - auto C = ConstantEmitter(*this).emitAbstract(refExpr->getLocation(), + auto C = ConstantEmitter(*this).emitAbstract(RefExpr->getLocation(), result.Val, resultType); // Make sure we emit a debug reference to the global variable. // This should probably fire even for - if (isa(value)) { - if (!getContext().DeclMustBeEmitted(cast(value))) - EmitDeclRefExprDbgValue(refExpr, result.Val); + if (isa(Value)) { + if (!getContext().DeclMustBeEmitted(cast(Value))) + EmitDeclRefExprDbgValue(RefExpr, result.Val); } else { - assert(isa(value)); - EmitDeclRefExprDbgValue(refExpr, result.Val); + assert(isa(Value)); + EmitDeclRefExprDbgValue(RefExpr, result.Val); } // If we emitted a reference constant, we need to dereference that. @@ -2201,8 +2201,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { // Load from __ptrauth. if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth()) { LV.getQuals().removePointerAuth(); - auto value = EmitLoadOfLValue(LV, Loc).getScalarVal(); - return RValue::get(EmitPointerAuthUnqualify(PtrAuth, value, LV.getType(), + auto Value = EmitLoadOfLValue(LV, Loc).getScalarVal(); + return RValue::get(EmitPointerAuthUnqualify(PtrAuth, Value, LV.getType(), LV.getAddress(), /*known nonnull*/ false)); } @@ -5582,8 +5582,8 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) { // Try to remember the original __ptrauth qualifier for loads of // function pointers. if (ICE->getCastKind() == CK_LValueToRValue) { - auto *SubExpr = ICE->getSubExpr(); - if (auto *PtrType = SubExpr->getType()->getAs()) { + const auto *SubExpr = ICE->getSubExpr(); + if (const auto *PtrType = SubExpr->getType()->getAs()) { auto Result = EmitOrigPointerRValue(E); QualType FunctionType = PtrType->getPointeeType(); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 0047ee4dca6fa..5e8831f47576b 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2203,15 +2203,14 @@ static bool isDeclRefKnownNonNull(CodeGenFunction &CGF, const ValueDecl *D) { static bool isLValueKnownNonNull(CodeGenFunction &CGF, const Expr *E) { E = E->IgnoreParens(); - if (auto *UO = dyn_cast(E)) { - if (UO->getOpcode() == UO_Deref) { + if (const auto *UO = dyn_cast(E)) + if (UO->getOpcode() == UO_Deref) return CGF.isPointerKnownNonNull(UO->getSubExpr()); - } - } - if (auto *DRE = dyn_cast(E)) { + if (const auto *DRE = dyn_cast(E)) return isDeclRefKnownNonNull(CGF, DRE->getDecl()); - } else if (auto *ME = dyn_cast(E)) { + + if (const auto *ME = dyn_cast(E)) { if (isa(ME->getMemberDecl())) return true; return isDeclRefKnownNonNull(CGF, ME->getMemberDecl()); @@ -2230,18 +2229,14 @@ bool CodeGenFunction::isPointerKnownNonNull(const Expr *E) { if (isa(E)) return true; - if (auto *UO = dyn_cast(E)) { - if (UO->getOpcode() == UO_AddrOf) { + if (const auto *UO = dyn_cast(E)) + if (UO->getOpcode() == UO_AddrOf) return isLValueKnownNonNull(*this, UO->getSubExpr()); - } - } - if (auto *CE = dyn_cast(E)) { + if (const auto *CE = dyn_cast(E)) if (CE->getCastKind() == CK_FunctionToPointerDecay || - CE->getCastKind() == CK_ArrayToPointerDecay) { + CE->getCastKind() == CK_ArrayToPointerDecay) return isLValueKnownNonNull(*this, CE->getSubExpr()); - } - } // Maybe honor __nonnull? diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index a2a014edbba12..990a6f437849e 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -198,11 +198,10 @@ emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV, SourceLocation Loc) { auto *Value = CGF.EmitLoadOfScalar(LV, Loc); CGPointerAuthInfo AuthInfo; - if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth()) { + if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth()) AuthInfo = CGF.EmitPointerAuthInfo(PtrAuth, LV.getAddress()); - } else { + else AuthInfo = getPointerAuthInfoForType(CGF.CGM, LV.getType()); - } return {Value, AuthInfo}; } @@ -213,12 +212,12 @@ CodeGenFunction::EmitOrigPointerRValue(const Expr *E) { assert(E->getType()->isSignableType()); E = E->IgnoreParens(); - if (auto *Load = dyn_cast(E)) { + if (const auto *Load = dyn_cast(E)) { if (Load->getCastKind() == CK_LValueToRValue) { E = Load->getSubExpr()->IgnoreParens(); // We're semantically required to not emit loads of certain DREs naively. - if (auto *RefExpr = dyn_cast(const_cast(E))) { + if (const auto *RefExpr = dyn_cast(E)) { if (auto Result = tryEmitAsConstant(RefExpr)) { // Fold away a use of an intermediate variable. if (!Result.isReference()) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 91bfe551268f3..dabe19d31652f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4313,10 +4313,10 @@ class CodeGenFunction : public CodeGenTypeCache { } bool isReference() const { return ValueAndIsReference.getInt(); } - LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const { + LValue getReferenceLValue(CodeGenFunction &CGF, const Expr *RefExpr) const { assert(isReference()); return CGF.MakeNaturalAlignAddrLValue(ValueAndIsReference.getPointer(), - refExpr->getType()); + RefExpr->getType()); } llvm::Constant *getValue() const { @@ -4325,7 +4325,7 @@ class CodeGenFunction : public CodeGenTypeCache { } }; - ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr); + ConstantEmission tryEmitAsConstant(const DeclRefExpr *RefExpr); ConstantEmission tryEmitAsConstant(const MemberExpr *ME); llvm::Value *emitScalarConstant(const ConstantEmission &Constant, Expr *E); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 515f874639509..7623eb2ecdc80 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8230,24 +8230,24 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, /// Handle the __ptrauth qualifier. static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, - const ParsedAttr &attr, Sema &S) { - auto AttributeName = attr.getAttrName()->getName(); - if (attr.getNumArgs() < 1 || attr.getNumArgs() > 3) { - S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_bad_arg_count) + const ParsedAttr &Attr, Sema &S) { + auto AttributeName = Attr.getAttrName()->getName(); + if (Attr.getNumArgs() < 1 || Attr.getNumArgs() > 3) { + S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_bad_arg_count) << AttributeName; - attr.setInvalid(); + Attr.setInvalid(); return; } - Expr *KeyArg = attr.getArgAsExpr(0); + Expr *KeyArg = Attr.getArgAsExpr(0); Expr *IsAddressDiscriminatedArg = - attr.getNumArgs() >= 2 ? attr.getArgAsExpr(1) : nullptr; + Attr.getNumArgs() >= 2 ? Attr.getArgAsExpr(1) : nullptr; Expr *ExtraDiscriminatorArg = - attr.getNumArgs() >= 3 ? attr.getArgAsExpr(2) : nullptr; + Attr.getNumArgs() >= 3 ? Attr.getArgAsExpr(2) : nullptr; unsigned Key; if (S.checkConstantPointerAuthKey(KeyArg, Key)) { - attr.setInvalid(); + Attr.setInvalid(); return; } assert(Key <= PointerAuthQualifier::MaxKey && "ptrauth key is out of range"); @@ -8261,26 +8261,26 @@ static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, ExtraDiscriminatorArg, Sema::PADAK_ExtraDiscPtrAuth, ExtraDiscriminator); if (IsInvalid) { - attr.setInvalid(); + Attr.setInvalid(); return; } if (!T->isSignableType() && !T->isDependentType()) { - S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T; - attr.setInvalid(); + S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_nonpointer) << T; + Attr.setInvalid(); return; } if (T.getPointerAuth()) { - S.Diag(attr.getLoc(), diag::err_ptrauth_qualifier_redundant) - << T << attr.getAttrName()->getName(); - attr.setInvalid(); + S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_redundant) + << T << Attr.getAttrName()->getName(); + Attr.setInvalid(); return; } if (!S.getLangOpts().PointerAuthIntrinsics) { - S.Diag(attr.getLoc(), diag::err_ptrauth_disabled) << attr.getRange(); - attr.setInvalid(); + S.Diag(Attr.getLoc(), diag::err_ptrauth_disabled) << Attr.getRange(); + Attr.setInvalid(); return; } diff --git a/clang/test/CodeGen/ptrauth-debuginfo.c b/clang/test/CodeGen/ptrauth-debuginfo.c index 214ecafca303c..6fa423a86c69b 100644 --- a/clang/test/CodeGen/ptrauth-debuginfo.c +++ b/clang/test/CodeGen/ptrauth-debuginfo.c @@ -19,13 +19,13 @@ struct A { struct A *createA(void); void f() { - __block struct A *__ptrauth(1, 1, 1236) ptr = createA(); + __block struct A *__ptrauth(0, 1, 1236) ptr = createA(); ^{ (void)ptr->value; }(); } // CHECK: !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type, -// CHECK-SAME: ptrAuthKey: 1, +// CHECK-NOT: ptrAuthKey // CHECK-SAME: ptrAuthIsAddressDiscriminated: true, // CHECK-SAME: ptrAuthExtraDiscriminator: 1236, // CHECK-SAME: ptrAuthIsaPointer: false, diff --git a/clang/test/CodeGen/ptrauth-qualifier.c b/clang/test/CodeGen/ptrauth-qualifier-const-init.c similarity index 99% rename from clang/test/CodeGen/ptrauth-qualifier.c rename to clang/test/CodeGen/ptrauth-qualifier-const-init.c index 5a664d296ce0e..2f87f49967369 100644 --- a/clang/test/CodeGen/ptrauth-qualifier.c +++ b/clang/test/CodeGen/ptrauth-qualifier-const-init.c @@ -1,7 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s -#include - // Constant initializers for data pointers. extern int external_int; diff --git a/clang/test/CodeGen/ptrauth-qualifier-function.c b/clang/test/CodeGen/ptrauth-qualifier-function.c index 133c396dcb9d4..b6bc50047a8b4 100644 --- a/clang/test/CodeGen/ptrauth-qualifier-function.c +++ b/clang/test/CodeGen/ptrauth-qualifier-function.c @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s -// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,CHECK-CXX %s +// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,TYPE %s +// RUN: %clang_cc1 %s -triple arm64-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,ZERO %s +// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,TYPE,CHECK-CXX %s #ifdef __cplusplus extern "C" { @@ -17,27 +18,31 @@ void test_assign_to_qualified() { // CHECK: [[ENTRY:.*]]:{{$}} // CHECK: [[FPTR:%.*]] = load ptr, ptr @fptr // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR]], null - // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN1:.*]], label %[[JOIN1:.*]] + // TYPE-NEXT: br i1 [[CMP]], label %[[RESIGN1:.*]], label %[[JOIN1:.*]] + // ZERO-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] - // CHECK: [[RESIGN1]]: - // CHECK-NEXT: [[FPTR2:%.*]] = ptrtoint ptr [[FPTR]] to i64 - // CHECK-NEXT: [[FPTR4:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR2]], i32 0, i64 18983, i32 0, i64 2712) - // CHECK-NEXT: [[FPTR5:%.*]] = inttoptr i64 [[FPTR4]] to ptr - // CHECK-NEXT: br label %[[JOIN1]] + // TYPE: [[RESIGN1]]: + // TYPE-NEXT: [[FPTR2:%.*]] = ptrtoint ptr [[FPTR]] to i64 + // TYPE-NEXT: [[FPTR4:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR2]], i32 0, i64 18983, i32 0, i64 2712) + // TYPE-NEXT: [[FPTR5:%.*]] = inttoptr i64 [[FPTR4]] to ptr + // TYPE-NEXT: br label %[[JOIN1]] - // CHECK: [[JOIN1]]: - // CHECK-NEXT: [[FPTR6:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR5]], %[[RESIGN1]] ] - // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR6]], null - // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] + // TYPE: [[JOIN1]]: + // TYPE-NEXT: [[FPTR6:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR5]], %[[RESIGN1]] ] + // TYPE-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR6]], null + // TYPE-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] // CHECK: [[RESIGN2]]: - // CHECK-NEXT: [[FPTR7:%.*]] = ptrtoint ptr [[FPTR6]] to i64 - // CHECK-NEXT: [[FPTR8:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR7]], i32 0, i64 2712, i32 0, i64 42) + // TYPE-NEXT: [[FPTR7:%.*]] = ptrtoint ptr [[FPTR6]] to i64 + // TYPE-NEXT: [[FPTR8:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR7]], i32 0, i64 2712, i32 0, i64 42) + // ZERO-NEXT: [[FPTR7:%.*]] = ptrtoint ptr [[FPTR]] to i64 + // ZERO-NEXT: [[FPTR8:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR7]], i32 0, i64 0, i32 0, i64 42) // CHECK-NEXT: [[FPTR9:%.*]] = inttoptr i64 [[FPTR8]] to ptr // CHECK-NEXT: br label %[[JOIN2]] // CHECK: [[JOIN2]] - // CHECK-NEXT: [[FPTR10:%.*]] = phi ptr [ null, %[[JOIN1]] ], [ [[FPTR9]], %[[RESIGN2]] ] + // TYPE-NEXT: [[FPTR10:%.*]] = phi ptr [ null, %[[JOIN1]] ], [ [[FPTR9]], %[[RESIGN2]] ] + // ZERO-NEXT: [[FPTR10:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR9]], %[[RESIGN2]] ] // CHECK-NEXT store void (i32)* [[FPTR10]], void (i32)** @f2ptr_42_discm } @@ -48,27 +53,31 @@ void test_assign_from_qualified() { // CHECK: [[ENTRY:.*]]:{{$}} // CHECK: [[FPTR:%.*]] = load ptr, ptr @f2ptr_42_discm // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR]], null - // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN1:.*]], label %[[JOIN1:.*]] + // TYPE-NEXT: br i1 [[CMP]], label %[[RESIGN1:.*]], label %[[JOIN1:.*]] + // ZERO-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] - // CHECK: [[RESIGN1]]: - // CHECK-NEXT: [[FPTR1:%.*]] = ptrtoint ptr [[FPTR]] to i64 - // CHECK-NEXT: [[FPTR2:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR1]], i32 0, i64 42, i32 0, i64 2712) - // CHECK-NEXT: [[FPTR3:%.*]] = inttoptr i64 [[FPTR2]] to ptr - // CHECK-NEXT: br label %[[JOIN1]] + // TYPE: [[RESIGN1]]: + // TYPE-NEXT: [[FPTR1:%.*]] = ptrtoint ptr [[FPTR]] to i64 + // TYPE-NEXT: [[FPTR2:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR1]], i32 0, i64 42, i32 0, i64 2712) + // TYPE-NEXT: [[FPTR3:%.*]] = inttoptr i64 [[FPTR2]] to ptr + // TYPE-NEXT: br label %[[JOIN1]] - // CHECK: [[JOIN1]]: - // CHECK-NEXT: [[FPTR4:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR3]], %[[RESIGN1]] ] - // CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR4]], null - // CHECK-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] + // TYPE: [[JOIN1]]: + // TYPE-NEXT: [[FPTR4:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR3]], %[[RESIGN1]] ] + // TYPE-NEXT: [[CMP:%.*]] = icmp ne ptr [[FPTR4]], null + // TYPE-NEXT: br i1 [[CMP]], label %[[RESIGN2:.*]], label %[[JOIN2:.*]] // CHECK: [[RESIGN2]]: - // CHECK-NEXT: [[FPTR6:%.*]] = ptrtoint ptr [[FPTR4]] to i64 - // CHECK-NEXT: [[FPTR7:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR6]], i32 0, i64 2712, i32 0, i64 18983) + // TYPE-NEXT: [[FPTR6:%.*]] = ptrtoint ptr [[FPTR4]] to i64 + // TYPE-NEXT: [[FPTR7:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR6]], i32 0, i64 2712, i32 0, i64 18983) + // ZERO-NEXT: [[FPTR6:%.*]] = ptrtoint ptr [[FPTR]] to i64 + // ZERO-NEXT: [[FPTR7:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[FPTR6]], i32 0, i64 42, i32 0, i64 0) // CHECK-NEXT: [[FPTR8:%.*]] = inttoptr i64 [[FPTR7]] to ptr // CHECK-NEXT: br label %[[JOIN2]] // CHECK: [[JOIN2]] - // CHECK-NEXT: [[FPTR9:%.*]] = phi ptr [ null, %[[JOIN1]] ], [ [[FPTR8]], %[[RESIGN2]] ] + // TYPE-NEXT: [[FPTR9:%.*]] = phi ptr [ null, %[[JOIN1]] ], [ [[FPTR8]], %[[RESIGN2]] ] + // ZERO-NEXT: [[FPTR9:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[FPTR8]], %[[RESIGN2]] ] // CHECK-NEXT store void ()* [[FPTR10]], void ()** @f2ptr_42_discm } @@ -76,7 +85,8 @@ void test_assign_from_qualified() { void test_const_ptr_function_call(void) { f_const_ptr(1); - // CHECK: call void ptrauth (ptr @f, i32 0, i64 2712)(i32 noundef 1) [ "ptrauth"(i32 0, i64 2712) ] + // TYPE: call void ptrauth (ptr @f, i32 0, i64 2712)(i32 noundef 1) [ "ptrauth"(i32 0, i64 2712) ] + // ZERO: call void ptrauth (ptr @f, i32 0)(i32 noundef 1) [ "ptrauth"(i32 0, i64 0) ] } #ifdef __cplusplus diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index 02e511a08ddeb..11543d560d6a4 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -1,7 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s -#include - #if __has_feature(ptrauth_qualifier) #warning __ptrauth qualifier enabled! // expected-warning@-1 {{__ptrauth qualifier enabled!}} @@ -33,6 +31,9 @@ int * __ptrauth(VALID_DATA_KEY, -1) invalid8; // expected-error{{address discrim int * __ptrauth(VALID_DATA_KEY, 1, -1) invalid9; // expected-error{{extra discriminator for __ptrauth must be between 0 and 65535; value is -1}} int * __ptrauth(VALID_DATA_KEY, 1, 100000) invalid10; // expected-error{{extra discriminator for __ptrauth must be between 0 and 65535; value is 100000}} int * __ptrauth(VALID_DATA_KEY, 1, nonConstantGlobal) invalid12; // expected-error{{argument to __ptrauth must be an integer constant expression}} +int * __ptrauth(VALID_DATA_KEY, nonConstantGlobal, 1000) invalid13; // expected-error{{argument to __ptrauth must be an integer constant expression}} +int * __ptrauth(nonConstantGlobal, 1, 1000) invalid14; // expected-error{{expression is not an integer constant expression}} +int * __ptrauth(VALID_DATA_KEY, 1, 1000, 12) invalid15; // expected-error{{qualifier must take between 1 and 3 arguments}} int * __ptrauth(VALID_DATA_KEY) valid0; int * __ptrauth(VALID_DATA_KEY) *valid1; diff --git a/clang/test/SemaCXX/ptrauth-template-parameters.cpp b/clang/test/SemaCXX/ptrauth-template-parameters.cpp index 2b09b70046d53..d8c1ea902460c 100644 --- a/clang/test/SemaCXX/ptrauth-template-parameters.cpp +++ b/clang/test/SemaCXX/ptrauth-template-parameters.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple arm64e-apple-ios -fsyntax-only -verify -fptrauth-intrinsics -std=c++20 %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics -std=c++11 %s template struct G { T __ptrauth(0,0,1234) test; From a8c855496fabcd5f605a035544a526f08bcab5c2 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 5 Aug 2024 16:56:41 -0700 Subject: [PATCH 08/19] Address review comments --- clang/lib/CodeGen/CGExpr.cpp | 2 +- clang/lib/CodeGen/CGPointerAuth.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index eca578de3c0a7..dd6885f9f0f20 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -527,7 +527,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { // initialized it. if (!Var->hasInitializer()) { Var->setInitializer(CGM.EmitNullConstant(E->getType())); - QualType RefType = M->getType(); + QualType RefType = M->getType().withoutLocalFastQualifiers(); if (RefType.getPointerAuth()) { // Use the qualifier of the reference temporary to sign the pointer. auto LV = MakeRawAddrLValue(Object.getPointer(), RefType, diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 990a6f437849e..dc80ba162bc6e 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -246,10 +246,7 @@ CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier DestQualifier, const Expr *E, Address DestStorageAddress) { assert(DestQualifier); - - auto Src = EmitOrigPointerRValue(E); - auto *Value = Src.first; - auto CurAuthInfo = Src.second; + auto [Value, CurAuthInfo] = EmitOrigPointerRValue(E); auto DestAuthInfo = EmitPointerAuthInfo(DestQualifier, DestStorageAddress); return emitPointerAuthResign(Value, E->getType(), CurAuthInfo, DestAuthInfo, From ad7f94e1be37d1d9283023e72a5eb92a6d55a36e Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 7 Aug 2024 10:58:59 -0700 Subject: [PATCH 09/19] Run tests with triple aarch64-linux-gnu --- clang/test/AST/ast-dump-ptrauth-json.cpp | 1 + clang/test/CodeGen/ptrauth-debuginfo.c | 3 ++ .../CodeGen/ptrauth-qualifier-const-init.c | 1 + .../test/CodeGen/ptrauth-qualifier-function.c | 15 +++--- .../CodeGen/ptrauth-qualifier-loadstore.c | 53 ++++++++++--------- .../CodeGenCXX/ptrauth-qualifier-struct.cpp | 49 ++++++++--------- clang/test/Sema/ptrauth-atomic-ops.c | 1 + clang/test/Sema/ptrauth-qualifier.c | 1 + clang/test/SemaCXX/ptrauth-qualifier.cpp | 1 + .../SemaCXX/ptrauth-template-parameters.cpp | 1 + clang/test/SemaObjC/ptrauth-qualifier.m | 1 + 11 files changed, 71 insertions(+), 56 deletions(-) diff --git a/clang/test/AST/ast-dump-ptrauth-json.cpp b/clang/test/AST/ast-dump-ptrauth-json.cpp index a85b1d8557335..8526598c491c1 100644 --- a/clang/test/AST/ast-dump-ptrauth-json.cpp +++ b/clang/test/AST/ast-dump-ptrauth-json.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -std=c++11 -ast-dump=json %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -std=c++11 -ast-dump=json %s | FileCheck %s // CHECK: "name": "__builtin_ptrauth_type_discriminator", // CHECK: "qualType": "int *__ptrauth(1,1,123)" diff --git a/clang/test/CodeGen/ptrauth-debuginfo.c b/clang/test/CodeGen/ptrauth-debuginfo.c index 6fa423a86c69b..b76baffadd9a1 100644 --- a/clang/test/CodeGen/ptrauth-debuginfo.c +++ b/clang/test/CodeGen/ptrauth-debuginfo.c @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -triple arm64-apple-ios \ // RUN: -fptrauth-calls -fptrauth-intrinsics -emit-llvm -fblocks \ // RUN: %s -debug-info-kind=limited -o - | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu \ +// RUN: -fptrauth-calls -fptrauth-intrinsics -emit-llvm -fblocks \ +// RUN: %s -debug-info-kind=limited -o - | FileCheck %s // Constant initializers for data pointers. extern int external_int; diff --git a/clang/test/CodeGen/ptrauth-qualifier-const-init.c b/clang/test/CodeGen/ptrauth-qualifier-const-init.c index 2f87f49967369..174f328628f19 100644 --- a/clang/test/CodeGen/ptrauth-qualifier-const-init.c +++ b/clang/test/CodeGen/ptrauth-qualifier-const-init.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s // Constant initializers for data pointers. extern int external_int; diff --git a/clang/test/CodeGen/ptrauth-qualifier-function.c b/clang/test/CodeGen/ptrauth-qualifier-function.c index b6bc50047a8b4..cd25b77a01548 100644 --- a/clang/test/CodeGen/ptrauth-qualifier-function.c +++ b/clang/test/CodeGen/ptrauth-qualifier-function.c @@ -1,6 +1,9 @@ // RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,TYPE %s +// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,TYPE %s // RUN: %clang_cc1 %s -triple arm64-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,ZERO %s +// RUN: %clang_cc1 %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,ZERO %s // RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,TYPE,CHECK-CXX %s +// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck --check-prefixes=CHECK,TYPE,CHECK-CXX %s #ifdef __cplusplus extern "C" { @@ -11,7 +14,7 @@ void (* __ptrauth(0, 0, 42) f2ptr_42_discm)(int); void f(int); void (* const __ptrauth(0, 0, 42) f_const_ptr)(int) = &f; -// CHECK-LABEL: define void @test_assign_to_qualified +// CHECK-LABEL: define {{.*}}void @test_assign_to_qualified void test_assign_to_qualified() { f2ptr_42_discm = (void (*)(int))fptr; @@ -46,7 +49,7 @@ void test_assign_to_qualified() { // CHECK-NEXT store void (i32)* [[FPTR10]], void (i32)** @f2ptr_42_discm } -// CHECK-LABEL: define void @test_assign_from_qualified +// CHECK-LABEL: define {{.*}}void @test_assign_from_qualified void test_assign_from_qualified() { fptr = (void (*)(void))f2ptr_42_discm; @@ -81,7 +84,7 @@ void test_assign_from_qualified() { // CHECK-NEXT store void ()* [[FPTR10]], void ()** @f2ptr_42_discm } -// CHECK-LABEL: define void @test_const_ptr_function_call() +// CHECK-LABEL: define {{.*}}void @test_const_ptr_function_call() void test_const_ptr_function_call(void) { f_const_ptr(1); @@ -94,7 +97,7 @@ void (* get_fptr(void))(int); void (* __ptrauth(0, 0, 42) f_const_ptr2)(int) = get_fptr(); void (* const __ptrauth(0, 1, 43) &f_ref)(int) = f_const_ptr2; -// CHECK-CXX-LABEL: define internal void @__cxx_global_var_init() +// CHECK-CXX-LABEL: define {{.*}}internal void @__cxx_global_var_init() // CHECK-CXX: [[ENTRY:.*]]: // CHECK-CXX: %[[CALL:.*]] = call ptr @get_fptr() // CHECK-CXX: %[[V0:.*]] = icmp ne ptr %[[CALL]], null @@ -110,7 +113,7 @@ void (* const __ptrauth(0, 1, 43) &f_ref)(int) = f_const_ptr2; // CHECK-CXX: %[[V4:.*]] = phi ptr [ null, %[[ENTRY]] ], [ %[[V3]], %[[RESIGN_NONNULL]] ] // CHECK-CXX: store ptr %[[V4]], ptr @f_const_ptr2, align 8 -// CHECK-CXX-LABEL: define internal void @__cxx_global_var_init.1() +// CHECK-CXX-LABEL: define {{.*}}internal void @__cxx_global_var_init.1() // CHECK-CXX: [[ENTRY:.*]]: // CHECK-CXX: %[[V0:.*]] = load ptr, ptr @f_const_ptr2, align 8 // CHECK-CXX: %[[V1:.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @_ZGR5f_ref_ to i64), i64 43) @@ -128,7 +131,7 @@ void (* const __ptrauth(0, 1, 43) &f_ref)(int) = f_const_ptr2; // CHECK-CXX: store ptr %[[V6]], ptr @_ZGR5f_ref_, align 8 // CHECK-CXX: store ptr @_ZGR5f_ref_, ptr @f_ref, align 8 -// CHECK-CXX-LABEL: define void @test_const_ptr_ref_function_call() +// CHECK-CXX-LABEL: define {{.*}}void @test_const_ptr_ref_function_call() void test_const_ptr_ref_function_call(void) { f_ref(1); diff --git a/clang/test/CodeGen/ptrauth-qualifier-loadstore.c b/clang/test/CodeGen/ptrauth-qualifier-loadstore.c index 41a87fba58e17..db259ed950fec 100644 --- a/clang/test/CodeGen/ptrauth-qualifier-loadstore.c +++ b/clang/test/CodeGen/ptrauth-qualifier-loadstore.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s #define IQ __ptrauth(1,0,50) #define AQ __ptrauth(1,1,50) @@ -22,7 +23,7 @@ extern void use_upf(func_t *ptr); // Data with address-independent qualifiers. -// CHECK-LABEL: define void @test_store_data_i_constant() +// CHECK-LABEL: define {{.*}}void @test_store_data_i_constant() void test_store_data_i_constant() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr @external_int to i64), i32 1, i64 50) @@ -36,7 +37,7 @@ void test_store_data_i_constant() { iqpi = &external_int; } -// CHECK-LABEL: define void @test_store_data_iu() +// CHECK-LABEL: define {{.*}}void @test_store_data_iu() void test_store_data_iu() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upi, @@ -61,7 +62,7 @@ void test_store_data_iu() { iqpi = global_upi; } -// CHECK-LABEL: define void @test_store_data_ia() +// CHECK-LABEL: define {{.*}}void @test_store_data_ia() void test_store_data_ia() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, @@ -107,7 +108,7 @@ void test_store_data_ia() { use_upi(iqpi = global_aqpi); } -// CHECK-LABEL: define void @test_store_data_ii_same() +// CHECK-LABEL: define {{.*}}void @test_store_data_ii_same() void test_store_data_ii_same() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, @@ -118,7 +119,7 @@ void test_store_data_ii_same() { iqpi = global_iqpi; } -// CHECK-LABEL: define void @test_store_data_ii_different() +// CHECK-LABEL: define {{.*}}void @test_store_data_ii_different() void test_store_data_ii_different() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, @@ -143,7 +144,7 @@ void test_store_data_ii_different() { iqpi = global_iqpi; } -// CHECK-LABEL: define void @test_store_data_ii_zero() +// CHECK-LABEL: define {{.*}}void @test_store_data_ii_zero() void test_store_data_ii_zero() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, @@ -168,7 +169,7 @@ void test_store_data_ii_zero() { global_iqpi = iqpi; } -// CHECK-LABEL: define void @test_load_data_i() +// CHECK-LABEL: define {{.*}}void @test_load_data_i() void test_load_data_i() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, @@ -205,7 +206,7 @@ void test_load_data_i() { // Data with address-discriminated qualifiers. -// CHECK-LABEL: define void @test_store_data_a_constant() +// CHECK-LABEL: define {{.*}}void @test_store_data_a_constant() void test_store_data_a_constant() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 @@ -222,7 +223,7 @@ void test_store_data_a_constant() { aqpi = &external_int; } -// CHECK-LABEL: define void @test_store_data_au() +// CHECK-LABEL: define {{.*}}void @test_store_data_au() void test_store_data_au() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upi, @@ -251,7 +252,7 @@ void test_store_data_au() { aqpi = global_upi; } -// CHECK-LABEL: define void @test_store_data_ai() +// CHECK-LABEL: define {{.*}}void @test_store_data_ai() void test_store_data_ai() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpi, @@ -280,7 +281,7 @@ void test_store_data_ai() { aqpi = global_iqpi; } -// CHECK-LABEL: define void @test_store_data_aa_same() +// CHECK-LABEL: define {{.*}}void @test_store_data_aa_same() void test_store_data_aa_same() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, @@ -311,7 +312,7 @@ void test_store_data_aa_same() { aqpi = global_aqpi; } -// CHECK-LABEL: define void @test_store_data_aa_different() +// CHECK-LABEL: define {{.*}}void @test_store_data_aa_different() void test_store_data_aa_different() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, @@ -342,7 +343,7 @@ void test_store_data_aa_different() { aqpi = global_aqpi; } -// CHECK-LABEL: define void @test_store_data_aa_zero() +// CHECK-LABEL: define {{.*}}void @test_store_data_aa_zero() void test_store_data_aa_zero() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, @@ -371,7 +372,7 @@ void test_store_data_aa_zero() { global_aqpi = aqpi; } -// CHECK-LABEL: define void @test_load_data_a() +// CHECK-LABEL: define {{.*}}void @test_load_data_a() void test_load_data_a() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpi, @@ -411,7 +412,7 @@ void test_load_data_a() { // Function with address-independent qualifiers. -// CHECK-LABEL: define void @test_store_function_i_constant() +// CHECK-LABEL: define {{.*}}void @test_store_function_i_constant() void test_store_function_i_constant() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @external_func, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 1, i64 50) @@ -424,7 +425,7 @@ void test_store_function_i_constant() { iqpf = &external_func; } -// CHECK-LABEL: define void @test_store_function_iu() +// CHECK-LABEL: define {{.*}}void @test_store_function_iu() void test_store_function_iu() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upf, @@ -449,7 +450,7 @@ void test_store_function_iu() { iqpf = global_upf; } -// CHECK-LABEL: define void @test_store_function_ia() +// CHECK-LABEL: define {{.*}}void @test_store_function_ia() void test_store_function_ia() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, @@ -495,7 +496,7 @@ void test_store_function_ia() { use_upf(iqpf = global_aqpf); } -// CHECK-LABEL: define void @test_store_function_ii_same() +// CHECK-LABEL: define {{.*}}void @test_store_function_ii_same() void test_store_function_ii_same() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, @@ -506,7 +507,7 @@ void test_store_function_ii_same() { iqpf = global_iqpf; } -// CHECK-LABEL: define void @test_store_function_ii_different() +// CHECK-LABEL: define {{.*}}void @test_store_function_ii_different() void test_store_function_ii_different() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, @@ -531,7 +532,7 @@ void test_store_function_ii_different() { iqpf = global_iqpf; } -// CHECK-LABEL: define void @test_load_function_i() +// CHECK-LABEL: define {{.*}}void @test_load_function_i() void test_load_function_i() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, @@ -568,7 +569,7 @@ void test_load_function_i() { // Function with address-discriminated qualifiers. -// CHECK-LABEL: define void @test_store_function_a_constant() +// CHECK-LABEL: define {{.*}}void @test_store_function_a_constant() void test_store_function_a_constant() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[V]] to i64 @@ -585,7 +586,7 @@ void test_store_function_a_constant() { aqpf = &external_func; } -// CHECK-LABEL: define void @test_store_function_au() +// CHECK-LABEL: define {{.*}}void @test_store_function_au() void test_store_function_au() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_upf, @@ -614,7 +615,7 @@ void test_store_function_au() { aqpf = global_upf; } -// CHECK-LABEL: define void @test_store_function_ai() +// CHECK-LABEL: define {{.*}}void @test_store_function_ai() void test_store_function_ai() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_iqpf, @@ -643,7 +644,7 @@ void test_store_function_ai() { aqpf = global_iqpf; } -// CHECK-LABEL: define void @test_store_function_aa_same() +// CHECK-LABEL: define {{.*}}void @test_store_function_aa_same() void test_store_function_aa_same() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, @@ -674,7 +675,7 @@ void test_store_function_aa_same() { aqpf = global_aqpf; } -// CHECK-LABEL: define void @test_store_function_aa_different() +// CHECK-LABEL: define {{.*}}void @test_store_function_aa_different() void test_store_function_aa_different() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, @@ -705,7 +706,7 @@ void test_store_function_aa_different() { aqpf = global_aqpf; } -// CHECK-LABEL: define void @test_load_function_a() +// CHECK-LABEL: define {{.*}}void @test_load_function_a() void test_load_function_a() { // CHECK: [[V:%.*]] = alloca ptr, // CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr @global_aqpf, diff --git a/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp b/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp index d38289cd7cef7..a45f4de95b421 100644 --- a/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp +++ b/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -std=c++11 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -std=c++11 -emit-llvm %s -o - | FileCheck -check-prefixes=CHECK,IOS %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -std=c++11 -emit-llvm %s -o - | FileCheck %s #define AQ __ptrauth(1,1,50) #define IQ __ptrauth(1,0,50) @@ -23,35 +24,35 @@ struct __attribute__((trivial_abi)) TrivialSA { // Check that TrivialSA is passed indirectly despite being annotated with // 'trivial_abi'. -// CHECK: define void @_Z18testParamTrivialSA9TrivialSA(ptr noundef %{{.*}}) +// CHECK: define {{.*}}void @_Z18testParamTrivialSA9TrivialSA(ptr noundef %{{.*}}) void testParamTrivialSA(TrivialSA a) { } -// CHECK: define void @_Z19testCopyConstructor2SA(ptr -// CHECK: call noundef ptr @_ZN2SAC1ERKS_( +// CHECK: define {{.*}}void @_Z19testCopyConstructor2SA(ptr +// CHECK: call {{.*}}@_ZN2SAC1ERKS_( -// CHECK: define linkonce_odr noundef ptr @_ZN2SAC1ERKS_( -// CHECK: call noundef ptr @_ZN2SAC2ERKS_( +// CHECK: define linkonce_odr {{.*}}@_ZN2SAC1ERKS_( +// CHECK: call {{.*}}@_ZN2SAC2ERKS_( void testCopyConstructor(SA a) { SA t = a; } -// CHECK: define void @_Z19testMoveConstructor2SA(ptr -// CHECK: call noundef ptr @_ZN2SAC1EOS_( +// CHECK: define {{.*}}void @_Z19testMoveConstructor2SA(ptr +// CHECK: call {{.*}}@_ZN2SAC1EOS_( -// CHECK: define linkonce_odr noundef ptr @_ZN2SAC1EOS_( -// CHECK: call noundef ptr @_ZN2SAC2EOS_( +// CHECK: define linkonce_odr {{.*}}@_ZN2SAC1EOS_( +// CHECK: call {{.*}}@_ZN2SAC2EOS_( void testMoveConstructor(SA a) { SA t = static_cast(a); } -// CHECK: define void @_Z18testCopyAssignment2SA(ptr +// CHECK: define {{.*}}void @_Z18testCopyAssignment2SA(ptr // CHECK: call noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSERKS_( -// CHECK: define linkonce_odr noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSERKS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// CHECK: define {{.*}}linkonce_odr noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSERKS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) // CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 // CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 // CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 @@ -73,10 +74,10 @@ void testCopyAssignment(SA a) { t = a; } -// CHECK: define void @_Z18testMoveAssignment2SA(ptr +// CHECK: define {{.*}}void @_Z18testMoveAssignment2SA(ptr // CHECK: call noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSEOS_( -// CHECK: define linkonce_odr noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSEOS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// CHECK: define {{.*}}linkonce_odr noundef nonnull align 8 dereferenceable(16) ptr @_ZN2SAaSEOS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) // CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 // CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 // CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 @@ -98,21 +99,21 @@ void testMoveAssignment(SA a) { t = static_cast(a); } -// CHECK: define void @_Z19testCopyConstructor2SI(i +// CHECK: define {{.*}}void @_Z19testCopyConstructor2SI(i // CHECK: call void @llvm.memcpy.p0.p0.i64( void testCopyConstructor(SI a) { SI t = a; } -// CHECK: define void @_Z19testMoveConstructor2SI( +// CHECK: define {{.*}}void @_Z19testMoveConstructor2SI( // CHECK: call void @llvm.memcpy.p0.p0.i64( void testMoveConstructor(SI a) { SI t = static_cast(a); } -// CHECK: define void @_Z18testCopyAssignment2SI( +// CHECK: define {{.*}}void @_Z18testCopyAssignment2SI( // CHECK: call void @llvm.memcpy.p0.p0.i64( void testCopyAssignment(SI a) { @@ -120,7 +121,7 @@ void testCopyAssignment(SI a) { t = a; } -// CHECK: define void @_Z18testMoveAssignment2SI( +// CHECK: define {{.*}}void @_Z18testMoveAssignment2SI( // CHECK: call void @llvm.memcpy.p0.p0.i64( void testMoveAssignment(SI a) { @@ -128,14 +129,14 @@ void testMoveAssignment(SI a) { t = static_cast(a); } -// CHECK: define linkonce_odr noundef ptr @_ZN2SAC2ERKS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) -// CHECK: %[[RETVAL:.*]] = alloca ptr, align 8 +// CHECK: define linkonce_odr {{.*}}@_ZN2SAC2ERKS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// IOS: %[[RETVAL:.*]] = alloca ptr, align 8 // CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 // CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 // CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 // CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 // CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 -// CHECK: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 +// IOS: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 // CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 // CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 // CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 @@ -147,14 +148,14 @@ void testMoveAssignment(SI a) { // CHECK: %[[V8:.*]] = ptrtoint ptr %[[V2]] to i64 // CHECK: %[[V9:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V8]], i32 1, i64 %[[V4]], i32 1, i64 %[[V6]]) -// CHECK: define linkonce_odr noundef ptr @_ZN2SAC2EOS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) -// CHECK: %[[RETVAL:.*]] = alloca ptr, align 8 +// CHECK: define linkonce_odr {{.*}}@_ZN2SAC2EOS_(ptr noundef nonnull align 8 dereferenceable(16) %[[THIS:.*]], ptr noundef nonnull align 8 dereferenceable(16) %0) +// IOS: %[[RETVAL:.*]] = alloca ptr, align 8 // CHECK: %[[THIS_ADDR:.*]] = alloca ptr, align 8 // CHECK: %[[_ADDR:.*]] = alloca ptr, align 8 // CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 // CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 // CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 -// CHECK: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 +// IOS: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 // CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 // CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 // CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 diff --git a/clang/test/Sema/ptrauth-atomic-ops.c b/clang/test/Sema/ptrauth-atomic-ops.c index 65b58379c8552..ccb9a1abcc14d 100644 --- a/clang/test/Sema/ptrauth-atomic-ops.c +++ b/clang/test/Sema/ptrauth-atomic-ops.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics %s #include diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index 11543d560d6a4..fbedbf1602d7f 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics %s #if __has_feature(ptrauth_qualifier) #warning __ptrauth qualifier enabled! diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp index 2cd9ebe356f61..8503f018d4790 100644 --- a/clang/test/SemaCXX/ptrauth-qualifier.cpp +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -std=c++11 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++11 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s #define AQ __ptrauth(1,1,50) #define AQ2 __ptrauth(1,1,51) diff --git a/clang/test/SemaCXX/ptrauth-template-parameters.cpp b/clang/test/SemaCXX/ptrauth-template-parameters.cpp index d8c1ea902460c..d450cd09e4929 100644 --- a/clang/test/SemaCXX/ptrauth-template-parameters.cpp +++ b/clang/test/SemaCXX/ptrauth-template-parameters.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics -std=c++11 %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics -std=c++11 %s template struct G { T __ptrauth(0,0,1234) test; diff --git a/clang/test/SemaObjC/ptrauth-qualifier.m b/clang/test/SemaObjC/ptrauth-qualifier.m index e5d424eaf92fd..79268c5583f26 100644 --- a/clang/test/SemaObjC/ptrauth-qualifier.m +++ b/clang/test/SemaObjC/ptrauth-qualifier.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics %s #if __has_feature(ptrauth_qualifier) #warning __ptrauth qualifier enabled! From c343b0e01001f7a93b0548b60224932a99d52cdf Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 13 Jan 2025 10:16:47 -0800 Subject: [PATCH 10/19] Fix check strings --- .../test/CodeGenCXX/ptrauth-qualifier-struct.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp b/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp index a45f4de95b421..7d6de50d926b5 100644 --- a/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp +++ b/clang/test/CodeGenCXX/ptrauth-qualifier-struct.cpp @@ -58,9 +58,9 @@ void testMoveConstructor(SA a) { // CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 // CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 // CHECK: %[[THISI:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 -// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THISI]], i32 0, i32 0 +// CHECK: %[[M0:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[THISI]], i32 0, i32 0 // CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 -// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[M02:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 // CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 // CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 // CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) @@ -83,9 +83,9 @@ void testCopyAssignment(SA a) { // CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]], align 8 // CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 // CHECK: %[[THISI:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 -// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THISI]], i32 0, i32 0 +// CHECK: %[[M0:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[THISI]], i32 0, i32 0 // CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 -// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[M02:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 // CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 // CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 // CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) @@ -137,9 +137,9 @@ void testMoveAssignment(SI a) { // CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 // CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 // IOS: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 -// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 +// CHECK: %[[M0:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 // CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 -// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[M02:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 // CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 // CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 // CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) @@ -156,9 +156,9 @@ void testMoveAssignment(SI a) { // CHECK: store ptr %[[V0:.*]], ptr %[[_ADDR]], align 8 // CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]], align 8 // IOS: store ptr %[[THIS1]], ptr %[[RETVAL]], align 8 -// CHECK: %[[M0:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 +// CHECK: %[[M0:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[THIS1]], i32 0, i32 0 // CHECK: %[[V1:.*]] = load ptr, ptr %[[_ADDR]], align 8 -// CHECK: %[[M02:.*]] = getelementptr inbounds %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 +// CHECK: %[[M02:.*]] = getelementptr inbounds nuw %[[STRUCT_SA]], ptr %[[V1]], i32 0, i32 0 // CHECK: %[[V2:.*]] = load ptr, ptr %[[M02]], align 8 // CHECK: %[[V3:.*]] = ptrtoint ptr %[[M02]] to i64 // CHECK: %[[V4:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V3]], i64 50) From fe015360ba4d016daa6a22b6fdb72438f110edf5 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 22 Jan 2025 11:33:17 -0800 Subject: [PATCH 11/19] Remove __ptrauth_restricted_intptr from docs and diagnostic message --- clang/include/clang/Basic/AttrDocs.td | 2 +- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Sema/SemaDecl.cpp | 3 +-- clang/lib/Sema/SemaObjCProperty.cpp | 3 +-- clang/lib/Sema/SemaType.cpp | 9 +++------ 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 22a405c609710..70a0b5a69b6c2 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2128,7 +2128,7 @@ Also see the documentation for `@available def PtrAuthDocs : Documentation { let Category = DocCatVariable; - let Heading = "__ptrauth, __ptrauth_restricted_intptr"; + let Heading = "__ptrauth"; let Content = [{ The ``__ptrauth`` qualifier allows the programmer to directly control how pointers are signed when they are stored in a particular variable. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c3c9ffcd1af42..7594a2b10a42c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -976,7 +976,7 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error< // __ptrauth qualifier def err_ptrauth_qualifier_invalid : Error< - "%select{return types|parameter types|properties}2 may not be qualified with %select{__ptrauth|__ptrauth_restricted_intptr}1; type is %0">; + "%select{return types|parameter types|properties}1 may not be qualified with __ptrauth; type is %0">; def err_ptrauth_qualifier_cast : Error< "cast types may not be qualified with __ptrauth; type is %0">; def err_ptrauth_qualifier_nonpointer : Error< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b1b78bb20d586..2e332f6390293 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15268,8 +15268,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // __ptrauth is forbidden on parameters. if (T.getPointerAuth()) { - Diag(NameLoc, diag::err_ptrauth_qualifier_invalid) - << T << (int)!T->isSignableType() << 1; + Diag(NameLoc, diag::err_ptrauth_qualifier_invalid) << T << 1; New->setInvalidDecl(); } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index f815b6d4d4836..b1dafb3cec94e 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -181,8 +181,7 @@ Decl *SemaObjC::ActOnProperty(Scope *S, SourceLocation AtLoc, TypeSourceInfo *TSI = SemaRef.GetTypeForDeclarator(FD.D); QualType T = TSI->getType(); if (T.getPointerAuth().isPresent()) { - Diag(AtLoc, diag::err_ptrauth_qualifier_invalid) - << T << (int)!T->isSignableType() << 2; + Diag(AtLoc, diag::err_ptrauth_qualifier_invalid) << T << 2; } if (!getOwnershipRule(Attributes)) { Attributes |= deducePropertyOwnershipFromType(SemaRef, T); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 2a51e46f7d654..7d7305432dd34 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2550,8 +2550,7 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { // __ptrauth is illegal on a function return type. if (T.getPointerAuth()) { - Diag(Loc, diag::err_ptrauth_qualifier_invalid) - << T << (int)!T->isSignableType() << 0; + Diag(Loc, diag::err_ptrauth_qualifier_invalid) << T << 0; return true; } @@ -2662,8 +2661,7 @@ QualType Sema::BuildFunctionType(QualType T, Invalid = true; } else if (ParamType.getPointerAuth()) { // __ptrauth is illegal on a function return type. - Diag(Loc, diag::err_ptrauth_qualifier_invalid) - << T << (int)!T->isSignableType() << 1; + Diag(Loc, diag::err_ptrauth_qualifier_invalid) << T << 1; Invalid = true; } @@ -4977,8 +4975,7 @@ 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 << (int)!T->isSignableType() << 0; + S.Diag(DeclType.Loc, diag::err_ptrauth_qualifier_invalid) << T << 0; } if (LangOpts.OpenCL) { From c965ad0c00cfd526add391bcda1ade907f59cb18 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 24 Feb 2025 11:51:19 -0800 Subject: [PATCH 12/19] Address review comments --- clang/docs/ReleaseNotes.rst | 2 ++ clang/include/clang/AST/Type.h | 2 +- .../clang/Basic/DiagnosticSemaKinds.td | 27 +++++++++--------- clang/lib/AST/TypePrinter.cpp | 6 ++-- clang/lib/CodeGen/CGClass.cpp | 6 ++-- clang/lib/CodeGen/CGDebugInfo.cpp | 2 +- clang/lib/CodeGen/CGExpr.cpp | 17 +++++------ clang/lib/CodeGen/CGExprConstant.cpp | 11 ++++---- clang/lib/CodeGen/CGPointerAuth.cpp | 23 ++++++++------- clang/lib/Sema/SemaType.cpp | 4 +-- clang/lib/Sema/TreeTransform.h | 2 +- clang/test/Sema/ptrauth-qualifier.c | 28 +++++++++---------- clang/test/SemaCXX/ptrauth-qualifier.cpp | 14 +++++----- clang/test/SemaObjC/ptrauth-qualifier.m | 20 ++++++------- 14 files changed, 83 insertions(+), 81 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 50d3bbbc97e91..310bc70cb796c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -193,6 +193,8 @@ X86 Support Arm and AArch64 Support ^^^^^^^^^^^^^^^^^^^^^^^ +- Support for __ptrauth type qualifier has been added. + Android Support ^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 239f16598a077..2cc1ffb957be6 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -810,7 +810,7 @@ class Qualifiers { "PointerAuthQualifier must be 32 bits"); static constexpr uint64_t PtrAuthShift = 32; - static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; + static constexpr uint64_t PtrAuthMask = UINT64_C(0xffffffff) << PtrAuthShift; static constexpr uint64_t UMask = 0x8; static constexpr uint64_t UShift = 3; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 63020e6f23152..0fb1773f788bc 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -982,22 +982,21 @@ def err_ptrauth_indirect_goto_addrlabel_arithmetic : Error< // __ptrauth qualifier def err_ptrauth_qualifier_invalid : Error< - "%select{return types|parameter types|properties}1 may not be qualified with __ptrauth; type is %0">; + "%select{return type|parameter type|property}1 may not be qualified with '__ptrauth'; type is %0">; def err_ptrauth_qualifier_cast : Error< - "cast types may not be qualified with __ptrauth; type is %0">; + "cannot cast to '__ptrauth'-qualified type %0">; def err_ptrauth_qualifier_nonpointer : Error< - "__ptrauth qualifier may only be applied to pointer types; type here is %0">; + "'__ptrauth' qualifier only applies to pointer types; %0 is invalid">; def err_ptrauth_qualifier_redundant : Error< "type %0 is already %1-qualified">; def err_ptrauth_qualifier_bad_arg_count : Error< - "%0 qualifier must take between 1 and 3 arguments">; + "'__ptrauth' qualifier must take between 1 and 3 arguments">; def err_ptrauth_arg_not_ice : Error< - "argument to __ptrauth must be an integer constant expression">; + "argument to '__ptrauth' must be an integer constant expression">; def err_ptrauth_address_discrimination_invalid : Error< - "address discrimination flag for __ptrauth must be 0 or 1; value is %0">; + "invalid address discrimination flag '%0'; '__ptrauth' requires '0' or '1'">; def err_ptrauth_extra_discriminator_invalid : Error< - "extra discriminator for __ptrauth must be between " - "0 and %1; value is %0">; + "invalid extra discriminator flag '%0'; '__ptrauth' requires a value between '0' and '%1'">; /// main() // static main() is not an error in C, just in C++. @@ -3963,7 +3962,7 @@ def note_cannot_use_trivial_abi_reason : Note< "it is polymorphic|" "it has a base of a non-trivial class type|it has a virtual base|" "it has a __weak field|it has a field of a non-trivial class type|" - "it has an address-discriminated __ptrauth field}1">; + "it has an address-discriminated '__ptrauth' field}1">; // Availability attribute def warn_availability_unknown_platform : Warning< @@ -5039,8 +5038,8 @@ def note_ovl_candidate_bad_ownership : Note< "__autoreleasing}5 ownership">; def note_ovl_candidate_bad_ptrauth : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " - "%ordinal8 argument (%3) has %select{no ptrauth|%5}4 qualifier," - " but parameter has %select{no ptrauth|%7}6 qualifier">; + "%ordinal8 argument (%3) has %select{no '__ptrauth'|%5}4 qualifier," + " but parameter has %select{no '__ptrauth'|%7}6 qualifier">; def note_ovl_candidate_bad_cvr_this : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "'this' argument has type %3, but method is not marked " @@ -6136,7 +6135,7 @@ def note_deleted_special_member_class_subobject : Note< "%select{default|corresponding|default|default|default}4 constructor}0|" "destructor}5" "%select{||s||}4" - "|is an ObjC pointer|has an address-discriminated ptrauth qualifier}6">; + "|is an ObjC pointer|has an address-discriminated '__ptrauth' qualifier}6">; def note_default_constructed_field : Note<"default constructed field %0 declared here">; def note_deleted_default_ctor_uninit_field : Note< @@ -8991,7 +8990,7 @@ def err_typecheck_incompatible_ptrauth : Error< "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" - " changes pointer-authentication of pointee type">; + " changes pointer authentication of pointee type">; def err_typecheck_comparison_of_distinct_blocks : Error< "comparison of distinct block types%diff{ ($ and $)|}0,1">; @@ -9399,7 +9398,7 @@ def ext_typecheck_cond_pointer_integer_mismatch : ExtWarn< "%diff{ ($ and $)|}0,1">, InGroup>; def err_typecheck_cond_incompatible_ptrauth : Error< - "__ptrauth qualification mismatch%diff{ ($ and $)|}0,1">; + "'__ptrauth' qualification mismatch%diff{ ($ and $)|}0,1">; def err_typecheck_choose_expr_requires_constant : Error< "'__builtin_choose_expr' requires a constant expression">; def warn_unused_expr : Warning<"expression result unused">, diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index d1d9aa76ac47f..f01b2fff2e893 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -2542,9 +2542,9 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { if (!(lifetime == Qualifiers::OCL_Strong && Policy.SuppressStrongLifetime)) return false; - if (PointerAuthQualifier PointerAuth = getPointerAuth()) - if (!PointerAuth.isEmptyWhenPrinted(Policy)) - return false; + if (PointerAuthQualifier PointerAuth = getPointerAuth(); + PointerAuth && !PointerAuth.isEmptyWhenPrinted(Policy)) + return false; return true; } diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 482db510d68e5..0ce13fde27770 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -929,9 +929,9 @@ namespace { Qualifiers Qual = F->getType().getQualifiers(); if (Qual.hasVolatile() || Qual.hasObjCLifetime()) return false; - if (PointerAuthQualifier Q = F->getType().getPointerAuth()) - if (Q.isAddressDiscriminated()) - return false; + if (PointerAuthQualifier Q = F->getType().getPointerAuth(); + Q && Q.isAddressDiscriminated()) + return false; return true; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index c340000817849..4a9d06d724ba8 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1068,7 +1068,7 @@ llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, Qc.getPointerAuth().authenticatesNullValues(); Qc.removePointerAuth(); assert(Qc.empty() && "Unknown type qualifier for debug info"); - auto *FromTy = getOrCreateType(QualType(T, 0), Unit); + llvm::DIType *FromTy = getOrCreateType(QualType(T, 0), Unit); return DBuilder.createPtrAuthQualifiedType(FromTy, Key, IsDiscr, ExtraDiscr, IsaPointer, AuthenticatesNullValues); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index c2377d6126b81..90a02c3097e1d 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -568,8 +568,8 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { QualType RefType = M->getType().withoutLocalFastQualifiers(); if (RefType.getPointerAuth()) { // Use the qualifier of the reference temporary to sign the pointer. - auto LV = MakeRawAddrLValue(Object.getPointer(), RefType, - Object.getAlignment()); + LValue LV = MakeRawAddrLValue(Object.getPointer(), RefType, + Object.getAlignment()); EmitScalarInit(E, M->getExtendingDecl(), LV, false); } else { EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/ true); @@ -1774,7 +1774,7 @@ CodeGenFunction::tryEmitAsConstant(const DeclRefExpr *RefExpr) { ConstantEmissionKind CEK; if (isa(Value)) { CEK = CEK_None; - } else if (auto *var = dyn_cast(Value)) { + } else if (const auto *var = dyn_cast(Value)) { CEK = checkVarTypeForConstantEmission(var->getType()); } else if (isa(Value)) { CEK = CEK_AsValueOnly; @@ -1831,8 +1831,8 @@ CodeGenFunction::tryEmitAsConstant(const DeclRefExpr *RefExpr) { } // Emit as a constant. - auto C = ConstantEmitter(*this).emitAbstract(RefExpr->getLocation(), - result.Val, resultType); + llvm::Constant *C = ConstantEmitter(*this).emitAbstract( + RefExpr->getLocation(), result.Val, resultType); // Make sure we emit a debug reference to the global variable. // This should probably fire even for @@ -2236,7 +2236,7 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { // Load from __ptrauth. if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth()) { LV.getQuals().removePointerAuth(); - auto Value = EmitLoadOfLValue(LV, Loc).getScalarVal(); + llvm::Value *Value = EmitLoadOfLValue(LV, Loc).getScalarVal(); return RValue::get(EmitPointerAuthUnqualify(PtrAuth, Value, LV.getType(), LV.getAddress(), /*known nonnull*/ false)); @@ -5735,9 +5735,10 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) { // Try to remember the original __ptrauth qualifier for loads of // function pointers. if (ICE->getCastKind() == CK_LValueToRValue) { - const auto *SubExpr = ICE->getSubExpr(); + const Expr *SubExpr = ICE->getSubExpr(); if (const auto *PtrType = SubExpr->getType()->getAs()) { - auto Result = EmitOrigPointerRValue(E); + std::pair Result = + EmitOrigPointerRValue(E); QualType FunctionType = PtrType->getPointeeType(); assert(FunctionType->isFunctionType()); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 8a38d9ad2d003..fa3d9a90e9d79 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2154,12 +2154,11 @@ llvm::Constant *ConstantLValueEmitter::tryEmit() { } // Apply pointer-auth signing from the destination type. - if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth()) { - if (!result.HasDestPointerAuth) { - value = Emitter.tryEmitConstantSignedPointer(value, PointerAuth); - if (!value) - return nullptr; - } + if (PointerAuthQualifier PointerAuth = DestType.getPointerAuth(); + PointerAuth && !result.HasDestPointerAuth) { + value = Emitter.tryEmitConstantSignedPointer(value, PointerAuth); + if (!value) + return nullptr; } // Convert to the appropriate type; this could be an lvalue for diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index dc80ba162bc6e..17ae754e744d1 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -196,7 +196,7 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) { static std::pair emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV, SourceLocation Loc) { - auto *Value = CGF.EmitLoadOfScalar(LV, Loc); + llvm::Value *Value = CGF.EmitLoadOfScalar(LV, Loc); CGPointerAuthInfo AuthInfo; if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth()) AuthInfo = CGF.EmitPointerAuthInfo(PtrAuth, LV.getAddress()); @@ -218,26 +218,26 @@ CodeGenFunction::EmitOrigPointerRValue(const Expr *E) { // We're semantically required to not emit loads of certain DREs naively. if (const auto *RefExpr = dyn_cast(E)) { - if (auto Result = tryEmitAsConstant(RefExpr)) { + if (ConstantEmission Result = tryEmitAsConstant(RefExpr)) { // Fold away a use of an intermediate variable. if (!Result.isReference()) return {Result.getValue(), getPointerAuthInfoForType(CGM, RefExpr->getType())}; // Fold away a use of an intermediate reference. - auto LV = Result.getReferenceLValue(*this, RefExpr); + LValue LV = Result.getReferenceLValue(*this, RefExpr); return emitLoadOfOrigPointerRValue(*this, LV, RefExpr->getLocation()); } } // Otherwise, load and use the pointer - auto LV = EmitCheckedLValue(E, CodeGenFunction::TCK_Load); + LValue LV = EmitCheckedLValue(E, CodeGenFunction::TCK_Load); return emitLoadOfOrigPointerRValue(*this, LV, E->getExprLoc()); } } // Fallback: just use the normal rules for the type. - auto *Value = EmitScalarExpr(E); + llvm::Value *Value = EmitScalarExpr(E); return {Value, getPointerAuthInfoForType(CGM, E->getType())}; } @@ -248,7 +248,8 @@ CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier DestQualifier, assert(DestQualifier); auto [Value, CurAuthInfo] = EmitOrigPointerRValue(E); - auto DestAuthInfo = EmitPointerAuthInfo(DestQualifier, DestStorageAddress); + CGPointerAuthInfo DestAuthInfo = + EmitPointerAuthInfo(DestQualifier, DestStorageAddress); return emitPointerAuthResign(Value, E->getType(), CurAuthInfo, DestAuthInfo, isPointerKnownNonNull(E)); } @@ -258,8 +259,9 @@ llvm::Value *CodeGenFunction::EmitPointerAuthQualify( QualType PointerType, Address DestStorageAddress, bool IsKnownNonNull) { assert(DestQualifier); - auto CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType); - auto DestAuthInfo = EmitPointerAuthInfo(DestQualifier, DestStorageAddress); + CGPointerAuthInfo CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType); + CGPointerAuthInfo DestAuthInfo = + EmitPointerAuthInfo(DestQualifier, DestStorageAddress); return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo, IsKnownNonNull); } @@ -269,8 +271,9 @@ llvm::Value *CodeGenFunction::EmitPointerAuthUnqualify( Address CurStorageAddress, bool IsKnownNonNull) { assert(CurQualifier); - auto CurAuthInfo = EmitPointerAuthInfo(CurQualifier, CurStorageAddress); - auto DestAuthInfo = getPointerAuthInfoForType(CGM, PointerType); + CGPointerAuthInfo CurAuthInfo = + EmitPointerAuthInfo(CurQualifier, CurStorageAddress); + CGPointerAuthInfo DestAuthInfo = getPointerAuthInfoForType(CGM, PointerType); return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo, IsKnownNonNull); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f1bfa660820b6..83c8bb3de2bb1 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8413,10 +8413,8 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, /// Handle the __ptrauth qualifier. static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, const ParsedAttr &Attr, Sema &S) { - auto AttributeName = Attr.getAttrName()->getName(); if (Attr.getNumArgs() < 1 || Attr.getNumArgs() > 3) { - S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_bad_arg_count) - << AttributeName; + S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_bad_arg_count); Attr.setInvalid(); return; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 50e91d36b0105..0afceaed4fec8 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5273,7 +5273,7 @@ QualType TreeTransform::RebuildQualifiedType(QualType T, return QualType(); } - auto LocalPointerAuth = Quals.getPointerAuth(); + PointerAuthQualifier LocalPointerAuth = Quals.getPointerAuth(); if (LocalPointerAuth.isPresent()) { if (T.getPointerAuth().isPresent()) { SemaRef.Diag(Loc, diag::err_ptrauth_qualifier_redundant) diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index fbedbf1602d7f..c3e47b0327384 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -23,16 +23,16 @@ int nonConstantGlobal = 5; __ptrauth int invalid0; // expected-error{{expected '('}} __ptrauth() int invalid1; // expected-error{{expected expression}} __ptrauth(INVALID_KEY) int invalid2; // expected-error{{200 does not identify a valid pointer authentication key for the current target}} -__ptrauth(VALID_DATA_KEY) int invalid3; // expected-error{{__ptrauth qualifier may only be applied to pointer types}} -__ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error{{__ptrauth qualifier may only be applied to pointer types}} +__ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int' is invalid}} +__ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int' is invalid}} int * (__ptrauth(VALID_DATA_KEY) invalid5); // expected-error{{expected identifier or '('}} expected-error{{expected ')'}} expected-note {{to match this '('}} int *__ptrauth(VALID_DATA_KEY) __ptrauth(VALID_DATA_KEY) invalid6; // expected-error{{type 'int *__ptrauth(2,0,0)' is already __ptrauth-qualified}} -int * __ptrauth(VALID_DATA_KEY, 2) invalid7; // expected-error{{address discrimination flag for __ptrauth must be 0 or 1; value is 2}} -int * __ptrauth(VALID_DATA_KEY, -1) invalid8; // expected-error{{address discrimination flag for __ptrauth must be 0 or 1; value is -1}} -int * __ptrauth(VALID_DATA_KEY, 1, -1) invalid9; // expected-error{{extra discriminator for __ptrauth must be between 0 and 65535; value is -1}} -int * __ptrauth(VALID_DATA_KEY, 1, 100000) invalid10; // expected-error{{extra discriminator for __ptrauth must be between 0 and 65535; value is 100000}} -int * __ptrauth(VALID_DATA_KEY, 1, nonConstantGlobal) invalid12; // expected-error{{argument to __ptrauth must be an integer constant expression}} -int * __ptrauth(VALID_DATA_KEY, nonConstantGlobal, 1000) invalid13; // expected-error{{argument to __ptrauth must be an integer constant expression}} +int * __ptrauth(VALID_DATA_KEY, 2) invalid7; // expected-error {{invalid address discrimination flag '2'; '__ptrauth' requires '0' or '1'}} +int * __ptrauth(VALID_DATA_KEY, -1) invalid8; // expected-error {{invalid address discrimination flag '-1'; '__ptrauth' requires '0' or '1'}} +int * __ptrauth(VALID_DATA_KEY, 1, -1) invalid9; // expected-error {{invalid extra discriminator flag '-1'; '__ptrauth' requires a value between '0' and '65535'}} +int * __ptrauth(VALID_DATA_KEY, 1, 100000) invalid10; // expected-error {{invalid extra discriminator flag '100000'; '__ptrauth' requires a value between '0' and '65535'}} +int * __ptrauth(VALID_DATA_KEY, 1, nonConstantGlobal) invalid12; // expected-error {{argument to '__ptrauth' must be an integer constant expression}} +int * __ptrauth(VALID_DATA_KEY, nonConstantGlobal, 1000) invalid13; // expected-error {{argument to '__ptrauth' must be an integer constant expression}} int * __ptrauth(nonConstantGlobal, 1, 1000) invalid14; // expected-error{{expression is not an integer constant expression}} int * __ptrauth(VALID_DATA_KEY, 1, 1000, 12) invalid15; // expected-error{{qualifier must take between 1 and 3 arguments}} @@ -60,11 +60,11 @@ intp redeclaration2 = 0; // expected-error{{redefinition o intp __ptrauth(VALID_DATA_KEY) redeclaration3; // expected-note {{previous definition}} intp redeclaration3 = 0; // expected-error{{redefinition of 'redeclaration3' with a different type: 'intp' (aka 'int *') vs '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} -void illegal0(intp __ptrauth(VALID_DATA_KEY)); // expected-error{{parameter types may not be qualified with __ptrauth}} -intp __ptrauth(VALID_DATA_KEY) illegal1(void); // expected-error{{return types may not be qualified with __ptrauth}} +void illegal0(intp __ptrauth(VALID_DATA_KEY)); // expected-error {{parameter type may not be qualified with '__ptrauth'; type is '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} +intp __ptrauth(VALID_DATA_KEY) illegal1(void); // expected-error {{return type may not be qualified with '__ptrauth'; type is '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} void test_code(intp p) { - p = (intp __ptrauth(VALID_DATA_KEY)) 0; // expected-error{{cast types may not be qualified with __ptrauth}} + p = (intp __ptrauth(VALID_DATA_KEY)) 0; // expected-error {{cannot cast to '__ptrauth'-qualified type '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} __ptrauth(VALID_DATA_KEY) intp pSpecial = p; pSpecial = p; @@ -72,11 +72,11 @@ void test_code(intp p) { pNormal = pSpecial; intp __ptrauth(VALID_DATA_KEY) *ppSpecial0 = &pSpecial; - intp __ptrauth(VALID_DATA_KEY) *ppSpecial1 = &pNormal; // expected-error {{initializing '__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') with an expression of type 'intp *' (aka 'int **') changes pointer-authentication of pointee type}} - intp *ppNormal0 = &pSpecial; // expected-error {{initializing 'intp *' (aka 'int **') with an expression of type '__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') changes pointer-authentication of pointee type}} + intp __ptrauth(VALID_DATA_KEY) *ppSpecial1 = &pNormal; // expected-error {{initializing '__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') with an expression of type 'intp *' (aka 'int **') changes pointer authentication of pointee type}} + intp *ppNormal0 = &pSpecial; // expected-error {{initializing 'intp *' (aka 'int **') with an expression of type '__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') changes pointer authentication of pointee type}} intp *ppNormal1 = &pNormal; - intp *pp5 = (p ? &pSpecial : &pNormal); // expected-error {{__ptrauth qualification mismatch ('__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') and 'intp *' (aka 'int **'))}} + intp *pp5 = (p ? &pSpecial : &pNormal); // expected-error {{'__ptrauth' qualification mismatch ('__ptrauth(2,0,0) intp *' (aka 'int *__ptrauth(2,0,0) *') and 'intp *' (aka 'int **'))}} } void test_array(void) { diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp index 8503f018d4790..c354ef28406dd 100644 --- a/clang/test/SemaCXX/ptrauth-qualifier.cpp +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -5,7 +5,7 @@ #define AQ2 __ptrauth(1,1,51) #define IQ __ptrauth(1,0,50) -struct __attribute__((trivial_abi)) AddrDisc { // expected-warning {{'trivial_abi' cannot be applied to 'AddrDisc'}} expected-note {{'trivial_abi' is disallowed on 'AddrDisc' because it has an address-discriminated __ptrauth field}} +struct __attribute__((trivial_abi)) AddrDisc { // expected-warning {{'trivial_abi' cannot be applied to 'AddrDisc'}} expected-note {{'trivial_abi' is disallowed on 'AddrDisc' because it has an address-discriminated '__ptrauth' field}} int * AQ m0; }; @@ -16,7 +16,7 @@ struct __attribute__((trivial_abi)) NoAddrDisc { namespace test_union { union U0 { - int * AQ f0; // expected-note 4 {{'U0' is implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + int * AQ f0; // expected-note 4 {{'U0' is implicitly deleted because variant field 'f0' has an address-discriminated '__ptrauth' qualifier}} // ptrauth fields that don't have an address-discriminated qualifier don't // delete the special functions. @@ -24,7 +24,7 @@ namespace test_union { }; union U1 { - int * AQ f0; // expected-note 8 {{'U1' is implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + int * AQ f0; // expected-note 8 {{'U1' is implicitly deleted because variant field 'f0' has an address-discriminated '__ptrauth' qualifier}} U1() = default; ~U1() = default; U1(const U1 &) = default; // expected-warning {{explicitly defaulted copy constructor is implicitly deleted}} expected-note 2 {{explicitly defaulted function was implicitly deleted here}} expected-note{{replace 'default'}} @@ -49,7 +49,7 @@ namespace test_union { // class. struct S0 { union { - int * AQ f0; // expected-note 4 {{' is implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + int * AQ f0; // expected-note 4 {{' is implicitly deleted because variant field 'f0' has an address-discriminated '__ptrauth' qualifier}} char f1; }; }; @@ -57,7 +57,7 @@ namespace test_union { struct S1 { union { union { - int * AQ f0; // expected-note 4 {{implicitly deleted because variant field 'f0' has an address-discriminated ptrauth qualifier}} + int * AQ f0; // expected-note 4 {{implicitly deleted because variant field 'f0' has an address-discriminated '__ptrauth' qualifier}} char f1; } u; // expected-note 4 {{'S1' is implicitly deleted because field 'u' has a deleted}} int f2; @@ -131,8 +131,8 @@ bool test_composite_type1(bool c, int * AQ * a0, int * AQ2 * a1) { return a0 == a1; // expected-error {{comparison of distinct pointer types ('int *__ptrauth(1,1,50) *' and 'int *__ptrauth(1,1,51) *')}} } -void test_bad_call_diag(void *AQ *ptr); // expected-note{{candidate function not viable: 1st argument ('void *__ptrauth(1,1,51) *') has __ptrauth(1,1,51) qualifier, but parameter has __ptrauth(1,1,50) qualifier}} expected-note{{candidate function not viable: 1st argument ('void **') has no ptrauth qualifier, but parameter has __ptrauth(1,1,50) qualifier}} -void test_bad_call_diag2(void **ptr); // expected-note{{1st argument ('void *__ptrauth(1,1,50) *') has __ptrauth(1,1,50) qualifier, but parameter has no ptrauth qualifier}} +void test_bad_call_diag(void *AQ *ptr); // expected-note{{candidate function not viable: 1st argument ('void *__ptrauth(1,1,51) *') has __ptrauth(1,1,51) qualifier, but parameter has __ptrauth(1,1,50) qualifier}} expected-note {{candidate function not viable: 1st argument ('void **') has no '__ptrauth' qualifier, but parameter has __ptrauth(1,1,50) qualifier}} +void test_bad_call_diag2(void **ptr); // expected-note {{candidate function not viable: 1st argument ('void *__ptrauth(1,1,50) *') has __ptrauth(1,1,50) qualifier, but parameter has no '__ptrauth' qualifier}} int test_call_diag() { void *AQ ptr1, *AQ2 ptr2, *ptr3; diff --git a/clang/test/SemaObjC/ptrauth-qualifier.m b/clang/test/SemaObjC/ptrauth-qualifier.m index 79268c5583f26..4836a653dd02f 100644 --- a/clang/test/SemaObjC/ptrauth-qualifier.m +++ b/clang/test/SemaObjC/ptrauth-qualifier.m @@ -11,23 +11,23 @@ @interface Foo // expected-note@-2 {{add a super class to fix this problem}} @property void *__ptrauth(1, 1, 1) invalid1; -// expected-error@-1 {{properties may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} +// expected-error@-1 {{property may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} @property void *__ptrauth(1, 0, 1) invalid2; -// expected-error@-1 {{properties may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} +// expected-error@-1 {{property may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} - (void *__ptrauth(1, 1, 1))invalid5; -// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} - (void *__ptrauth(1, 0, 1))invalid6; -// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} - (void)invalid9:(void *__ptrauth(1, 1, 1))a; -// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} // expected-note@-2 {{method 'invalid9:' declared here}} - (void)invalid10:(void *__ptrauth(1, 0, 1))a; -// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} // expected-note@-2 {{method 'invalid10:' declared here}} @end @@ -36,21 +36,21 @@ @implementation Foo // expected-warning@-1 2{{method definition for}} - (void *__ptrauth(1, 1, 1))invalid13 { -// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} return 0; } - (void *__ptrauth(1, 0, 1))invalid14 { -// expected-error@-1 {{return types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} +// expected-error@-1 {{return type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} return 0; } - (void)invalid17:(void *__ptrauth(1, 1, 1))a { -// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,1,1)'}} +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,1,1)'}} } - (void)invalid18:(void *__ptrauth(1, 0, 1))a { -// expected-error@-1 {{parameter types may not be qualified with __ptrauth; type is 'void *__ptrauth(1,0,1)'}} +// expected-error@-1 {{parameter type may not be qualified with '__ptrauth'; type is 'void *__ptrauth(1,0,1)'}} } @end From ae8a37efa7a43539743b90652ceb08bb80d94f7a Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Thu, 27 Feb 2025 14:17:51 -0800 Subject: [PATCH 13/19] Use enum_select --- .../clang/Basic/DiagnosticSemaKinds.td | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0fb1773f788bc..b52f44a8c7b0d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8979,17 +8979,17 @@ def err_typecheck_incompatible_ownership : Error< "|%diff{casting $ to type $|casting between types}0,1}2" " changes retain/release properties of pointer">; def err_typecheck_incompatible_ptrauth : Error< - "%select{%diff{assigning $ to $|assigning to different types}1,0" - "|%diff{passing $ to parameter of type $|" - "passing to parameter of different type}0,1" - "|%diff{returning $ from a function with result type $|" - "returning from function with different return type}0,1" - "|%diff{converting $ to type $|converting between types}0,1" - "|%diff{initializing $ with an expression of type $|" - "initializing with expression of different type}0,1" - "|%diff{sending $ to parameter of type $|" - "sending to parameter of different type}0,1" - "|%diff{casting $ to type $|casting between types}0,1}2" + "%enum_select{%Assigning{%diff{assigning $ to $|assigning to different types}1,0}" + "|%Passing{%diff{passing $ to parameter of type $|" + "passing to parameter of different type}0,1}" + "|%Returning{%diff{returning $ from a function with result type $|" + "returning from function with different return type}0,1}" + "|%Converting{%diff{converting $ to type $|converting between types}0,1}" + "|%Initializing{%diff{initializing $ with an expression of type $|" + "initializing with expression of different type}0,1}" + "|%Sending{%diff{sending $ to parameter of type $|" + "sending to parameter of different type}0,1}" + "|%Casting{%diff{casting $ to type $|casting between types}0,1}}2" " changes pointer authentication of pointee type">; def err_typecheck_comparison_of_distinct_blocks : Error< "comparison of distinct block types%diff{ ($ and $)|}0,1">; From c95c9dd57c2777adaf4f6b94889d84fbc158db1b Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Thu, 13 Mar 2025 14:53:29 -0700 Subject: [PATCH 14/19] Address review comments --- .../clang/Basic/DiagnosticParseKinds.td | 3 +++ .../include/clang/Basic/DiagnosticSemaKinds.td | 2 -- clang/include/clang/Basic/Features.def | 2 +- clang/lib/Parse/ParseDecl.cpp | 9 +++++++-- clang/lib/Sema/SemaCast.cpp | 3 +++ clang/lib/Sema/SemaChecking.cpp | 10 ++-------- clang/lib/Sema/SemaDecl.cpp | 8 ++++---- clang/lib/Sema/SemaDeclCXX.cpp | 9 +++++---- clang/lib/Sema/SemaType.cpp | 7 ++----- clang/test/Parser/ptrauth-qualifier.c | 18 ++++++++++++++++++ clang/test/Preprocessor/ptrauth_extension.c | 13 +++++++++++++ clang/test/Preprocessor/ptrauth_feature.c | 8 -------- clang/test/Sema/ptrauth-qualifier.c | 3 --- .../SemaCXX/ptrauth-template-parameters.cpp | 1 + 14 files changed, 59 insertions(+), 37 deletions(-) create mode 100644 clang/test/Parser/ptrauth-qualifier.c create mode 100644 clang/test/Preprocessor/ptrauth_extension.c diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index c513dab810d1f..2895f9d16bc90 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1710,6 +1710,9 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning< "argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">, InGroup; +def err_ptrauth_qualifier_bad_arg_count : Error< + "'__ptrauth' qualifier must take between 1 and 3 arguments">; + def warn_cuda_attr_lambda_position : Warning< "nvcc does not allow '__%0__' to appear after the parameter list in lambdas">, InGroup; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b52f44a8c7b0d..5cef9d340476d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -989,8 +989,6 @@ def err_ptrauth_qualifier_nonpointer : Error< "'__ptrauth' qualifier only applies to pointer types; %0 is invalid">; def err_ptrauth_qualifier_redundant : Error< "type %0 is already %1-qualified">; -def err_ptrauth_qualifier_bad_arg_count : Error< - "'__ptrauth' qualifier must take between 1 and 3 arguments">; def err_ptrauth_arg_not_ice : Error< "argument to '__ptrauth' must be an integer constant expression">; def err_ptrauth_address_discrimination_invalid : Error< diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 86171137ef90d..96001dd740218 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -107,7 +107,7 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics) -FEATURE(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics) +EXTENSION(ptrauth_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/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 851c80fddf45e..88b0676f1e93b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3405,7 +3405,7 @@ void Parser::DistributeCLateParsedAttrs(Decl *Dcl, /// ('__ptrauth') '(' constant-expression /// (',' constant-expression)[opt] /// (',' constant-expression)[opt] ')' -void Parser::ParsePtrauthQualifier(ParsedAttributes &attrs) { +void Parser::ParsePtrauthQualifier(ParsedAttributes &Attrs) { assert(Tok.is(tok::kw___ptrauth)); IdentifierInfo *KwName = Tok.getIdentifierInfo(); @@ -3428,7 +3428,12 @@ void Parser::ParsePtrauthQualifier(ParsedAttributes &attrs) { T.consumeClose(); SourceLocation EndLoc = T.getCloseLocation(); - attrs.addNew(KwName, SourceRange(KwLoc, EndLoc), + if (ArgExprs.empty() || ArgExprs.size() > 3) { + Diag(KwLoc, diag::err_ptrauth_qualifier_bad_arg_count); + return; + } + + Attrs.addNew(KwName, SourceRange(KwLoc, EndLoc), /*scope*/ nullptr, SourceLocation(), ArgExprs.data(), ArgExprs.size(), ParsedAttr::Form::Keyword(/*IsAlignAs=*/false, diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 7b8a9742bc402..1b2defc1e051c 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -72,6 +72,9 @@ namespace { // Preceding an expression by a parenthesized type name converts the // value of the expression to the unqualified, non-atomic version of // the named type. + // Don't drop __ptrauth qualifiers. We want to treat casting to a + // __ptrauth-qualified type as an error instead of implicitly ignoring + // the qualifier. if (!S.Context.getLangOpts().ObjC && !DestType->isRecordType() && !DestType->isArrayType() && !DestType.getPointerAuth()) { DestType = DestType.getAtomicUnqualifiedType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 39a63a3b46788..bcbcc6ce9950d 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1577,18 +1577,12 @@ bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg, }; if (*Result < 0 || *Result > Max) { - llvm::SmallString<32> Value; - { - llvm::raw_svector_ostream str(Value); - str << *Result; - } - if (IsAddrDiscArg) Diag(Arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid) - << Value; + << Result->getExtValue(); else Diag(Arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid) - << Value << Max; + << Result->getExtValue() << Max; return false; }; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d31d034c30426..938c47f1f038a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -19379,10 +19379,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } else if (FT.getQualifiers().getObjCLifetime() == Qualifiers::OCL_Weak) { Record->setArgPassingRestrictions( RecordArgPassingKind::CanNeverPassInRegs); - } else if (PointerAuthQualifier Q = FT.getPointerAuth()) { - if (Q.isAddressDiscriminated()) - Record->setArgPassingRestrictions( - RecordArgPassingKind::CanNeverPassInRegs); + } else if (PointerAuthQualifier Q = FT.getPointerAuth(); + Q && Q.isAddressDiscriminated()) { + Record->setArgPassingRestrictions( + RecordArgPassingKind::CanNeverPassInRegs); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9318ee3066575..0a139e556ee9a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9363,7 +9363,7 @@ struct SpecialMemberDeletionInfo bool shouldDeleteForVariantObjCPtrMember(FieldDecl *FD, QualType FieldType); - bool shouldDeleteForVariantPtrAuthMember(FieldDecl *FD, QualType FieldType); + bool shouldDeleteForVariantPtrAuthMember(const FieldDecl *FD); bool visitBase(CXXBaseSpecifier *Base) { return shouldDeleteForBase(Base); } bool visitField(FieldDecl *Field) { return shouldDeleteForField(Field); } @@ -9534,7 +9534,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForVariantObjCPtrMember( } bool SpecialMemberDeletionInfo::shouldDeleteForVariantPtrAuthMember( - FieldDecl *FD, QualType FieldType) { + const FieldDecl *FD) { + QualType FieldType = S.Context.getBaseElementType(FD->getType()); // Copy/move constructors/assignment operators are deleted if the field has an // address-discriminated ptrauth qualifier. PointerAuthQualifier Q = FieldType.getPointerAuth(); @@ -9594,7 +9595,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (inUnion() && shouldDeleteForVariantObjCPtrMember(FD, FieldType)) return true; - if (inUnion() && shouldDeleteForVariantPtrAuthMember(FD, FieldType)) + if (inUnion() && shouldDeleteForVariantPtrAuthMember(FD)) return true; if (CSM == CXXSpecialMemberKind::DefaultConstructor) { @@ -9660,7 +9661,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (shouldDeleteForVariantObjCPtrMember(&*UI, UnionFieldType)) return true; - if (shouldDeleteForVariantPtrAuthMember(&*UI, UnionFieldType)) + if (shouldDeleteForVariantPtrAuthMember(&*UI)) return true; if (!UnionFieldType.isConstQualified()) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 83c8bb3de2bb1..6435251034279 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8413,12 +8413,9 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, /// Handle the __ptrauth qualifier. static void HandlePtrAuthQualifier(ASTContext &Ctx, QualType &T, const ParsedAttr &Attr, Sema &S) { - if (Attr.getNumArgs() < 1 || Attr.getNumArgs() > 3) { - S.Diag(Attr.getLoc(), diag::err_ptrauth_qualifier_bad_arg_count); - Attr.setInvalid(); - return; - } + assert((Attr.getNumArgs() > 0 && Attr.getNumArgs() <= 3) && + "__ptrauth qualifier takes between 1 and 3 arguments"); Expr *KeyArg = Attr.getArgAsExpr(0); Expr *IsAddressDiscriminatedArg = Attr.getNumArgs() >= 2 ? Attr.getArgAsExpr(1) : nullptr; diff --git a/clang/test/Parser/ptrauth-qualifier.c b/clang/test/Parser/ptrauth-qualifier.c new file mode 100644 index 0000000000000..2071ac6c2d661 --- /dev/null +++ b/clang/test/Parser/ptrauth-qualifier.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics %s + +#if __aarch64__ +#define VALID_DATA_KEY 2 +#else +#error Provide these constants if you port this test +#endif + +int * __ptrauth(VALID_DATA_KEY) valid0; + +typedef int *intp; + +int nonConstantGlobal = 5; + +__ptrauth int invalid0; // expected-error{{expected '('}} +__ptrauth() int invalid1; // expected-error{{expected expression}} +int * __ptrauth(VALID_DATA_KEY, 1, 1000, 12) invalid12; // expected-error{{qualifier must take between 1 and 3 arguments}} diff --git a/clang/test/Preprocessor/ptrauth_extension.c b/clang/test/Preprocessor/ptrauth_extension.c new file mode 100644 index 0000000000000..d6b79187ba62d --- /dev/null +++ b/clang/test/Preprocessor/ptrauth_extension.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-intrinsics | \ +// RUN: FileCheck %s --check-prefixes=INTRIN + +// RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-calls | \ +// RUN: FileCheck %s --check-prefixes=NOINTRIN + +#if __has_extension(ptrauth_qualifier) +// INTRIN: has_ptrauth_qualifier +void has_ptrauth_qualifier() {} +#else +// NOINTRIN: no_ptrauth_qualifier +void no_ptrauth_qualifier() {} +#endif diff --git a/clang/test/Preprocessor/ptrauth_feature.c b/clang/test/Preprocessor/ptrauth_feature.c index 25eae4528d4f2..a440791d6cc69 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -123,14 +123,6 @@ void has_ptrauth_indirect_gotos() {} void no_ptrauth_indirect_gotos() {} #endif -#if __has_feature(ptrauth_qualifier) -// INTRIN: has_ptrauth_qualifier -void has_ptrauth_qualifier() {} -#else -// NOINTRIN: no_ptrauth_qualifier -void no_ptrauth_qualifier() {} -#endif - #if __has_feature(ptrauth_elf_got) // ELFGOT: has_ptrauth_elf_got void has_ptrauth_elf_got() {} diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index c3e47b0327384..e7554a5d653a3 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -20,8 +20,6 @@ typedef int *intp; int nonConstantGlobal = 5; -__ptrauth int invalid0; // expected-error{{expected '('}} -__ptrauth() int invalid1; // expected-error{{expected expression}} __ptrauth(INVALID_KEY) int invalid2; // expected-error{{200 does not identify a valid pointer authentication key for the current target}} __ptrauth(VALID_DATA_KEY) int invalid3; // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int' is invalid}} __ptrauth(VALID_DATA_KEY) int *invalid4; // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int' is invalid}} @@ -34,7 +32,6 @@ int * __ptrauth(VALID_DATA_KEY, 1, 100000) invalid10; // expected-error {{invali int * __ptrauth(VALID_DATA_KEY, 1, nonConstantGlobal) invalid12; // expected-error {{argument to '__ptrauth' must be an integer constant expression}} int * __ptrauth(VALID_DATA_KEY, nonConstantGlobal, 1000) invalid13; // expected-error {{argument to '__ptrauth' must be an integer constant expression}} int * __ptrauth(nonConstantGlobal, 1, 1000) invalid14; // expected-error{{expression is not an integer constant expression}} -int * __ptrauth(VALID_DATA_KEY, 1, 1000, 12) invalid15; // expected-error{{qualifier must take between 1 and 3 arguments}} int * __ptrauth(VALID_DATA_KEY) valid0; int * __ptrauth(VALID_DATA_KEY) *valid1; diff --git a/clang/test/SemaCXX/ptrauth-template-parameters.cpp b/clang/test/SemaCXX/ptrauth-template-parameters.cpp index d450cd09e4929..d3ea2bb48c4a6 100644 --- a/clang/test/SemaCXX/ptrauth-template-parameters.cpp +++ b/clang/test/SemaCXX/ptrauth-template-parameters.cpp @@ -13,6 +13,7 @@ template struct Indirect { }; void f3() { + // FIXME: consider loosening the restrictions so that the first two cases are accepted. Indirect one; // expected-note@-1{{in instantiation of template class 'Indirect' requested here}} Indirect two; From 636e81578c20b799aa845b5a888afca1012ee3fa Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 21 Mar 2025 11:31:41 -0700 Subject: [PATCH 15/19] Add tests for rejecting template parameters being passed to __ptrauth --- clang/test/SemaCXX/ptrauth-template-parameters.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/SemaCXX/ptrauth-template-parameters.cpp b/clang/test/SemaCXX/ptrauth-template-parameters.cpp index d3ea2bb48c4a6..ee23d3f2ec456 100644 --- a/clang/test/SemaCXX/ptrauth-template-parameters.cpp +++ b/clang/test/SemaCXX/ptrauth-template-parameters.cpp @@ -12,6 +12,13 @@ template struct Indirect { // expected-note@-2{{in instantiation of template class 'G' requested here}} }; +template +struct TemplateParameters { + void * __ptrauth(K, 0, 100) m1; // expected-error {{expression is not an integer constant expression}} + void * __ptrauth(0, A, 100) m2; // expected-error {{argument to '__ptrauth' must be an integer constant expression}} + void * __ptrauth(0, 0, D) m3; // expected-error {{argument to '__ptrauth' must be an integer constant expression}} +}; + void f3() { // FIXME: consider loosening the restrictions so that the first two cases are accepted. Indirect one; From 02299cbbde43d7cc41ac6e0d9e259118db4a167d Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 31 Mar 2025 12:03:14 -0700 Subject: [PATCH 16/19] Add test for _Generic, overloadable functions, and arrays --- clang/test/Sema/ptrauth-qualifier.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index e7554a5d653a3..99d16b062ca6f 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s -// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s #if __has_feature(ptrauth_qualifier) #warning __ptrauth qualifier enabled! @@ -15,6 +15,7 @@ #endif int * __ptrauth(VALID_DATA_KEY) valid0; +int *ptr0; typedef int *intp; @@ -45,6 +46,9 @@ int * __ptrauth(VALID_DATA_KEY, (_Bool) 1) valid8; int * __ptrauth(VALID_DATA_KEY, 1, 0) valid9; int * __ptrauth(VALID_DATA_KEY, 1, 65535) valid10; +int * __ptrauth(VALID_DATA_KEY) array0[10]; +int (* __ptrauth(VALID_DATA_KEY) array1)[10]; + extern intp redeclaration0; // expected-note {{previous declaration}} extern intp __ptrauth(VALID_DATA_KEY) redeclaration0; // expected-error{{redeclaration of 'redeclaration0' with a different type: '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)') vs 'intp' (aka 'int *')}} @@ -60,6 +64,14 @@ intp redeclaration3 = 0; // expected-error{{redefinition o void illegal0(intp __ptrauth(VALID_DATA_KEY)); // expected-error {{parameter type may not be qualified with '__ptrauth'; type is '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} intp __ptrauth(VALID_DATA_KEY) illegal1(void); // expected-error {{return type may not be qualified with '__ptrauth'; type is '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} +static_assert(_Generic(typeof(valid0), int * __ptrauth(VALID_DATA_KEY) : 1, int * : 0, default : 0)); +static_assert(_Generic(typeof(valid0), int * __ptrauth(VALID_CODE_KEY) : 0, default : 1)); +static_assert(_Generic(typeof_unqual(valid0), int * __ptrauth(VALID_DATA_KEY) : 0, int * : 1, default : 0)); +static_assert(_Generic(valid0, int * __ptrauth(VALID_DATA_KEY) : 0, int * : 1, default : 0)); // expected-warning {{association of type 'int *__ptrauth(2,0,0)' will never be selected}} + +static_assert(_Generic(array0, int * __ptrauth(VALID_DATA_KEY) * : 1, default : 0)); +static_assert(_Generic(*array1, int * : 1, default : 0)); + void test_code(intp p) { p = (intp __ptrauth(VALID_DATA_KEY)) 0; // expected-error {{cannot cast to '__ptrauth'-qualified type '__ptrauth(2,0,0) intp' (aka 'int *__ptrauth(2,0,0)')}} @@ -81,3 +93,11 @@ void test_array(void) { intp __ptrauth(VALID_DATA_KEY) *ppSpecial0 = pSpecialArray; intp __ptrauth(VALID_DATA_KEY) *ppSpecial1 = &pSpecialArray[0]; } + +__attribute__((overloadable)) int overload_func(int **); +__attribute__((overloadable)) float overload_func(int * __ptrauth(VALID_DATA_KEY) *); + +static_assert(_Generic(typeof(overload_func(&ptr0)), int : 1, default : 0)); +static_assert(_Generic(typeof(overload_func(&valid0)), float : 1, default : 0)); + +void func(int array[__ptrauth(VALID_DATA_KEY) 10]); // expected-error {{'__ptrauth' qualifier only applies to pointer types; 'int[10]' is invalid}} From 24f33cd795ba02b1bab52c310e1520f0a3e672d6 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 9 Apr 2025 17:41:14 -0700 Subject: [PATCH 17/19] Add tests for constexpr, lambda, and concept Check that ptrauth qualifiers match exactly in qualification conversion. --- clang/lib/Sema/SemaOverload.cpp | 4 ++ clang/test/SemaCXX/ptrauth-qualifier.cpp | 58 +++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 3c4671f0b5883..509755898a97a 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3657,6 +3657,10 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType, ToQuals.removeObjCGCAttr(); } + // __ptrauth qualifiers must match exactly. + if (FromQuals.getPointerAuth() != ToQuals.getPointerAuth()) + return false; + // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals, Ctx)) diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp index c354ef28406dd..d0c99056c7710 100644 --- a/clang/test/SemaCXX/ptrauth-qualifier.cpp +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++11 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s -// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++11 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++20 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++20 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s #define AQ __ptrauth(1,1,50) #define AQ2 __ptrauth(1,1,51) @@ -140,3 +140,57 @@ int test_call_diag() { test_bad_call_diag(&ptr3); // expected-error {{no matching function for call to 'test_bad_call_diag'}} test_bad_call_diag2(&ptr1); // expected-error {{no matching function for call to 'test_bad_call_diag2'}} } + +namespace test_constexpr { + constexpr int i = 100; + constexpr const int * AQ p = &i; + constexpr const int * const AQ *pp = &p; + constexpr int i1 = **((const int * const AQ *)pp); + constexpr int i2 = **((const int * const AQ2 *)pp); + // expected-error@-1 {{constexpr variable 'i2' must be initialized by a constant expression}} + // expected-note@-2 {{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}} +} + +namespace test_lambda { + void test() { + int * AQ v0; + int * AQ *v1; + + [v0, v1]() { + static_assert(__is_same(decltype(v0), int * AQ)); + static_assert(__is_same(decltype(v1), int * AQ *)); + }(); + + [v2 = v0, v3 = v1]() { + static_assert(__is_same(decltype(v2), int *)); + static_assert(__is_same(decltype(v3), int * AQ *)); + }(); + } +} + +namespace test_concept { + template struct is_qualified { + static constexpr bool value = false; + }; + + template struct is_qualified { + static constexpr bool value = true; + }; + + template + concept Ptrauthable = is_qualified::value; + // expected-note@-1 {{because 'is_qualified::value' evaluated to false}} + // expected-note@-2 {{because 'is_qualified::value' evaluated to false}} + + template + requires(Ptrauthable) + struct S {}; + // expected-note@-2 {{because 'int *' does not satisfy 'Ptrauthable'}} + // expected-note@-3 {{because 'int *__ptrauth(1,1,51)' does not satisfy 'Ptrauthable'}} + + S s0; + S s1; + // expected-error@-1 {{constraints not satisfied for class template 'S' [with T = int *]}} + S s1; + // expected-error@-1 {{constraints not satisfied for class template 'S' [with T = int *__ptrauth(1,1,51)]}} +} From 9cbf8b0ff16d9e4733989825e245a6b3a83b975d Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 9 Apr 2025 18:00:16 -0700 Subject: [PATCH 18/19] Add more tests for concept --- clang/test/SemaCXX/ptrauth-qualifier.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp index d0c99056c7710..a7dc6ae2ffe86 100644 --- a/clang/test/SemaCXX/ptrauth-qualifier.cpp +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -179,8 +179,8 @@ namespace test_concept { template concept Ptrauthable = is_qualified::value; - // expected-note@-1 {{because 'is_qualified::value' evaluated to false}} - // expected-note@-2 {{because 'is_qualified::value' evaluated to false}} + // expected-note@-1 2 {{because 'is_qualified::value' evaluated to false}} + // expected-note@-2 2 {{because 'is_qualified::value' evaluated to false}} template requires(Ptrauthable) @@ -193,4 +193,21 @@ namespace test_concept { // expected-error@-1 {{constraints not satisfied for class template 'S' [with T = int *]}} S s1; // expected-error@-1 {{constraints not satisfied for class template 'S' [with T = int *__ptrauth(1,1,51)]}} + + template + requires(Ptrauthable) + void func(T *); + // expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int *]}} + // expected-note@-3 {{because 'int *' does not satisfy 'Ptrauthable'}} + // expected-note@-3 {{candidate template ignored: constraints not satisfied [with T = int *__ptrauth(1,1,51)]}} + // expected-note@-5 {{because 'int *__ptrauth(1,1,51)' does not satisfy 'Ptrauthable'}} + + void test() { + int * AQ p0; + int *p1; + int * AQ2 p2; + func(&p0); + func(&p1); // expected-error {{no matching function for call to 'func'}} + func(&p2); // expected-error {{no matching function for call to 'func'}} + } } From 45e5b93a556ca10afe1fd5246d407c764544f6c5 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 14 Apr 2025 18:13:47 -0700 Subject: [PATCH 19/19] Implement mangling/demangling __ptrauth on Windows Add mangling/demangling tests. --- clang/lib/AST/MicrosoftMangle.cpp | 13 +++++ .../CodeGenCXX/mangle-itanium-ptrauth.cpp | 12 +++++ clang/test/CodeGenCXX/mangle-ms-ptrauth.cpp | 17 +++++++ libcxxabi/test/test_demangle.pass.cpp | 3 ++ .../include/llvm/Demangle/MicrosoftDemangle.h | 8 ++++ .../llvm/Demangle/MicrosoftDemangleNodes.h | 22 ++++++++- llvm/lib/Demangle/MicrosoftDemangle.cpp | 48 ++++++++++++++++++- llvm/lib/Demangle/MicrosoftDemangleNodes.cpp | 10 ++++ llvm/test/Demangle/ms-ptrauth.test | 12 +++++ 9 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGenCXX/mangle-itanium-ptrauth.cpp create mode 100644 clang/test/CodeGenCXX/mangle-ms-ptrauth.cpp create mode 100644 llvm/test/Demangle/ms-ptrauth.test diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index fe34251688a98..b55d288429d8b 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -430,6 +430,7 @@ class MicrosoftCXXNameMangler { void mangleRefQualifier(RefQualifierKind RefQualifier); void manglePointerCVQualifiers(Qualifiers Quals); void manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType); + void manglePointerAuthQualifier(Qualifiers Quals); void mangleUnscopedTemplateName(GlobalDecl GD); void @@ -2334,6 +2335,17 @@ void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals, Out << 'F'; } +void MicrosoftCXXNameMangler::manglePointerAuthQualifier(Qualifiers Quals) { + PointerAuthQualifier PointerAuth = Quals.getPointerAuth(); + if (!PointerAuth) + return; + + Out << "__ptrauth"; + mangleNumber(PointerAuth.getKey()); + mangleNumber(PointerAuth.isAddressDiscriminated()); + mangleNumber(PointerAuth.getExtraDiscriminator()); +} + void MicrosoftCXXNameMangler::manglePointerCVQualifiers(Qualifiers Quals) { // ::= P # no qualifiers // ::= Q # const @@ -3366,6 +3378,7 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals, QualType PointeeType = T->getPointeeType(); manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); + manglePointerAuthQualifier(Quals); // For pointer size address spaces, go down the same type mangling path as // non address space types. diff --git a/clang/test/CodeGenCXX/mangle-itanium-ptrauth.cpp b/clang/test/CodeGenCXX/mangle-itanium-ptrauth.cpp new file mode 100644 index 0000000000000..88d80423c3764 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-itanium-ptrauth.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -std=c++11 -fptrauth-intrinsics -fptrauth-calls -emit-llvm -o - -triple=arm64-apple-ios %s | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -fptrauth-intrinsics -fptrauth-calls -emit-llvm -o - -triple=aarch64-linux-gnu %s | FileCheck %s + +// CHECK: define {{.*}}void @_Z3fooPU9__ptrauthILj3ELb1ELj234EEPi( +void foo(int * __ptrauth(3, 1, 234) *) {} + +template +void foo(T t) {} + +// CHECK: define weak_odr void @_Z3fooIPU9__ptrauthILj1ELb0ELj64EEPiEvT_( +template void foo(int * __ptrauth(1, 0, 64) *); + diff --git a/clang/test/CodeGenCXX/mangle-ms-ptrauth.cpp b/clang/test/CodeGenCXX/mangle-ms-ptrauth.cpp new file mode 100644 index 0000000000000..95e5efa472dfd --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-ms-ptrauth.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++11 -fptrauth-intrinsics -fptrauth-calls -emit-llvm -o - -triple=aarch64-windows-msvc %s | FileCheck %s + +template +struct S {}; + +// CHECK: @"?s@@3U?$S@PE__ptrauth1A@ENC@AH@@A" = +S s; + +// CHECK: define dso_local void @"?foo@@YAXPEAPE__ptrauth20OK@AH@Z"( +void foo(int * __ptrauth(3, 1, 234) *) {} + +template +void foo(T t) {} + +// CHECK: define weak_odr dso_local void @"??$foo@PEAPE__ptrauth0A@EA@AH@@YAXPEAPE__ptrauth0A@EA@AH@Z"( +template void foo(int * __ptrauth(1, 0, 64) *); + diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp index e9c74f70a094b..f1dd552b9a83d 100644 --- a/libcxxabi/test/test_demangle.pass.cpp +++ b/libcxxabi/test/test_demangle.pass.cpp @@ -30247,6 +30247,9 @@ const char* cases[][2] = { {"_Z1fDSDRm", "f(_Sat unsigned long _Fract)"}, {"_Z11bfloat16addDF16bDF16b", "bfloat16add(std::bfloat16_t, std::bfloat16_t)"}, + + {"_Z3fooPU9__ptrauthILj3ELb1ELj234EEPi", "foo(int* __ptrauth<3u, true, 234u>*)"}, + {"_Z3fooIPU9__ptrauthILj1ELb0ELj64EEPiEvT_", "void foo*>(int* __ptrauth<1u, false, 64u>*)"}, // clang-format on }; diff --git a/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/llvm/include/llvm/Demangle/MicrosoftDemangle.h index 276efa7603690..b9a25e361eec0 100644 --- a/llvm/include/llvm/Demangle/MicrosoftDemangle.h +++ b/llvm/include/llvm/Demangle/MicrosoftDemangle.h @@ -173,6 +173,14 @@ class Demangler { Qualifiers demanglePointerExtQualifiers(std::string_view &MangledName); + bool isMemberPointer(std::string_view MangledName, bool &Error); + + std::optional + demanglePointerAuthQualifier(std::string_view &MangledName); + + PointerAuthQualifierNode * + createPointerAuthQualifier(std::string_view &MangledName); + // Parser functions. This is a recursive-descent parser. TypeNode *demangleType(std::string_view &MangledName, QualifierMangleMode QMM); diff --git a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h index 09b9d947464ae..d72fb47cd9b04 100644 --- a/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h +++ b/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h @@ -253,7 +253,8 @@ enum class NodeKind { LocalStaticGuardVariable, FunctionSymbol, VariableSymbol, - SpecialTableSymbol + SpecialTableSymbol, + PointerAuthQualifier, }; struct Node { @@ -295,6 +296,7 @@ struct SymbolNode; struct FunctionSymbolNode; struct VariableSymbolNode; struct SpecialTableSymbolNode; +struct PointerAuthQualifierNode; struct TypeNode : public Node { explicit TypeNode(NodeKind K) : Node(K) {} @@ -467,6 +469,8 @@ struct PointerTypeNode : public TypeNode { // If this is a member pointer, this is the class that the member is in. QualifiedNameNode *ClassParent = nullptr; + PointerAuthQualifierNode *PointerAuthQualifier = nullptr; + // Represents a type X in "a pointer to X", "a reference to X", or // "rvalue-reference to X" TypeNode *Pointee = nullptr; @@ -625,6 +629,22 @@ struct FunctionSymbolNode : public SymbolNode { FunctionSignatureNode *Signature = nullptr; }; +struct PointerAuthQualifierNode : public Node { + PointerAuthQualifierNode() : Node(NodeKind::PointerAuthQualifier) {} + + // __ptrauth takes three arguments: + // - key + // - isAddressDiscriminated + // - extra discriminator + static constexpr unsigned NumArgs = 3; + typedef std::array ArgArray; + + void output(OutputBuffer &OB, OutputFlags Flags) const override; + + // List of arguments. + NodeArrayNode *Components = nullptr; +}; + } // namespace ms_demangle } // namespace llvm diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp index 6be8b0fe73996..1e1bf7698683d 100644 --- a/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -66,7 +66,7 @@ static bool startsWith(std::string_view S, std::string_view PrefixA, return llvm::itanium_demangle::starts_with(S, Prefix); } -static bool isMemberPointer(std::string_view MangledName, bool &Error) { +bool Demangler::isMemberPointer(std::string_view MangledName, bool &Error) { Error = false; const char F = MangledName.front(); MangledName.remove_prefix(1); @@ -107,6 +107,7 @@ static bool isMemberPointer(std::string_view MangledName, bool &Error) { consumeFront(MangledName, 'E'); // 64-bit consumeFront(MangledName, 'I'); // restrict consumeFront(MangledName, 'F'); // unaligned + demanglePointerAuthQualifier(MangledName); if (MangledName.empty()) { Error = true; @@ -2094,6 +2095,8 @@ PointerTypeNode *Demangler::demanglePointerType(std::string_view &MangledName) { Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName); Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); + Pointer->PointerAuthQualifier = createPointerAuthQualifier(MangledName); + Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle); return Pointer; } @@ -2142,6 +2145,49 @@ Demangler::demanglePointerExtQualifiers(std::string_view &MangledName) { return Quals; } +std::optional +Demangler::demanglePointerAuthQualifier(std::string_view &MangledName) { + if (!consumeFront(MangledName, "__ptrauth")) + return std::nullopt; + + constexpr unsigned NumArgs = PointerAuthQualifierNode::NumArgs; + PointerAuthQualifierNode::ArgArray Array; + + for (unsigned I = 0; I < NumArgs; ++I) { + bool IsNegative = false; + uint64_t Value = 0; + std::tie(Value, IsNegative) = demangleNumber(MangledName); + if (IsNegative) + return std::nullopt; + + Array[I] = Value; + } + + return Array; +} + +PointerAuthQualifierNode * +Demangler::createPointerAuthQualifier(std::string_view &MangledName) { + constexpr unsigned NumArgs = PointerAuthQualifierNode::NumArgs; + std::optional Vals = + demanglePointerAuthQualifier(MangledName); + + if (!Vals) + return nullptr; + + PointerAuthQualifierNode *PtrAuthQual = + Arena.alloc(); + NodeArrayNode *Array = Arena.alloc(); + PtrAuthQual->Components = Array; + Array->Count = NumArgs; + Array->Nodes = Arena.allocArray(NumArgs); + + for (unsigned I = 0; I < NumArgs; ++I) + Array->Nodes[I] = Arena.alloc((*Vals)[I], false); + + return PtrAuthQual; +} + ArrayTypeNode *Demangler::demangleArrayType(std::string_view &MangledName) { assert(MangledName.front() == 'Y'); MangledName.remove_prefix(1); diff --git a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp index ec6e67058c683..61e4961c714bc 100644 --- a/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp @@ -521,6 +521,9 @@ void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const { assert(false); } outputQualifiers(OB, Quals, false, false); + + if (PointerAuthQualifier) + PointerAuthQualifier->output(OB, Flags); } void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const { @@ -591,6 +594,13 @@ void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { Signature->outputPost(OB, Flags); } +void PointerAuthQualifierNode::output(OutputBuffer &OB, + OutputFlags Flags) const { + OB << "__ptrauth("; + Components->output(OB, Flags); + OB << ")"; +} + void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const { const char *AccessSpec = nullptr; bool IsStatic = true; diff --git a/llvm/test/Demangle/ms-ptrauth.test b/llvm/test/Demangle/ms-ptrauth.test new file mode 100644 index 0000000000000..18a9f37bec67a --- /dev/null +++ b/llvm/test/Demangle/ms-ptrauth.test @@ -0,0 +1,12 @@ +; RUN: llvm-undname < %s | FileCheck %s + +; CHECK-NOT: Invalid mangled name + +?s@@3U?$S@PE__ptrauth1A@ENC@AH@@A +; CHECK: struct S s + +?foo@@YAXPEAPE__ptrauth20OK@AH@Z +; CHECK: void __cdecl foo(int *__ptrauth(3, 1, 234)*) + +??$foo@PEAPE__ptrauth0A@EA@AH@@YAXPEAPE__ptrauth0A@EA@AH@Z +; CHECK: void __cdecl foo(int *__ptrauth(1, 0, 64)*)