https://github.com/ojhunt created https://github.com/llvm/llvm-project/pull/153912
For backwards compatibility reasons the ptrauth_qualifier and ptrauth_intrinsic features need to be testable with __has_feature() on Apple platforms, but for other platforms this backwards compatibility issue does not exist. This PR resolves these issues by making the ptrauth_qualifier and ptrauth_intrinsic tests conditional upon a darwin target. This also allows us to revert the ptrauth_qualifier check from an extension to a feature test again, as is required on these platforms. At the same time we introduce a new predefined macro __PTRAUTH__ that answers the same question as __has_feature(ptrauth_qualifier) and __has_feature(ptrauth_intrinsic) as those tests are synonymous and only exist separately for compatibility reasons. The requirement to test for the __PTRAUTH__ macro also resolves the hazard presented by mixing the ptrauth_qualifier flag (that impacts ABI and security policies) with -pedantics-errors, which makes __has_extension return false for all extensions. >From ea731927d6bdf85a3cdb333b756447658f2c2ea6 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Fri, 15 Aug 2025 18:40:12 -0700 Subject: [PATCH] [clang][PAC] Make ptrauth_qualifier and ptrauth_intrinsic Darwin only features For backwards compatibility reasons the ptrauth_qualifier and ptrauth_intrinsic features need to be testable with __has_feature() on Apple platforms, but for other platforms this backwards compatibility issue does not exist. This PR resolves these issues by making the ptrauth_qualifier and ptrauth_intrinsic tests conditional upon a darwin target. This also allows us to revert the ptrauth_qualifier check from an extension to a feature test again, as is required on these platforms. At the same time we introduce a new predefined macro __PTRAUTH__ that answers the same question as __has_feature(ptrauth_qualifier) and __has_feature(ptrauth_intrinsic) as those tests are synonymous and only exist separately for compatibility reasons. The requirement to test for the __PTRAUTH__ macro also resolves the hazard presented by mixing the ptrauth_qualifier flag (that impacts ABI and security policies) with -pedantics-errors, which makes __has_extension return false for all extensions. --- clang/include/clang/Basic/Features.def | 4 +-- clang/lib/Frontend/FrontendActions.cpp | 1 + clang/lib/Frontend/InitPreprocessor.cpp | 3 +++ clang/lib/Headers/ptrauth.h | 4 +-- clang/lib/Lex/PPMacroExpansion.cpp | 1 + clang/test/Preprocessor/ptrauth_extension.c | 30 ++++++++++++++++++--- clang/test/Preprocessor/ptrauth_feature.c | 2 +- clang/test/Sema/ptrauth-qualifier.c | 16 +++++++++-- clang/test/SemaObjC/ptrauth-qualifier.m | 16 +++++++++-- 9 files changed, 64 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index b9efc6a6a2e9d..6f414105d7c36 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -147,8 +147,8 @@ FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type)) 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) -EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics) +FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics && Target.getTriple().isOSDarwin()) +FEATURE(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics && Target.getTriple().isOSDarwin()) FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls) FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns) FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination) diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 685a9bbf2cde9..d29a08c43fc12 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -1159,6 +1159,7 @@ void DumpCompilerOptionsAction::ExecuteAction() { raw_ostream &OS = *OSP; const Preprocessor &PP = CI.getPreprocessor(); const LangOptions &LangOpts = PP.getLangOpts(); + const TargetInfo &Target = CI.getTarget(); // FIXME: Rather than manually format the JSON (which is awkward due to // needing to remove trailing commas), this should make use of a JSON library. diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 008a35d5265e1..accddfebc0f6f 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1528,6 +1528,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, #undef TARGET_OS } + if (LangOpts.PointerAuthIntrinsics) + Builder.defineMacro("__PTRAUTH__"); + // Get other target #defines. TI.getTargetDefines(LangOpts, Builder); } diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 7f7d387cbdfda..f902ca1e3bbd3 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -95,7 +95,7 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; __ptrauth qualifier; the compiler will perform this check automatically. */ -#if __has_feature(ptrauth_intrinsics) +#if __has_feature(ptrauth_intrinsics) || defined(__PTRAUTH__) /* Strip the signature from a value without authenticating it. @@ -388,6 +388,6 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; #define __ptrauth_objc_isa_uintptr #define __ptrauth_objc_super_pointer -#endif /* __has_feature(ptrauth_intrinsics) */ +#endif /* __has_feature(ptrauth_intrinsics) || defined(__PTRAUTH__) */ #endif /* __PTRAUTH_H */ diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 6f12ac80d677e..f9dfd0eb14bc0 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1089,6 +1089,7 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, /// specified by the identifier as a standard language feature. static bool HasFeature(const Preprocessor &PP, StringRef Feature) { const LangOptions &LangOpts = PP.getLangOpts(); + const TargetInfo &Target = PP.getTargetInfo(); // Normalize the feature name, __foo__ becomes foo. if (Feature.starts_with("__") && Feature.ends_with("__") && diff --git a/clang/test/Preprocessor/ptrauth_extension.c b/clang/test/Preprocessor/ptrauth_extension.c index d6b79187ba62d..3267b0786c28f 100644 --- a/clang/test/Preprocessor/ptrauth_extension.c +++ b/clang/test/Preprocessor/ptrauth_extension.c @@ -4,10 +4,32 @@ // 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 +// RUN: %clang_cc1 -E %s -DIS_DARWIN -triple=arm64e-apple-darwin -fptrauth-intrinsics | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,INTRIN_MAC + +// RUN: %clang_cc1 -E %s -DIS_DARWIN -triple=arm64e-apple-darwin -fptrauth-calls | \ +// RUN: FileCheck %s --check-prefixes=NOINTRIN + +#if defined(IS_DARWIN) && __has_extension(ptrauth_qualifier) +// INTRIN_MAC: has_ptrauth_qualifier1 +void has_ptrauth_qualifier1() {} +#ifndef __PTRAUTH__ +#error ptrauth_qualifier extension present without predefined test macro +#endif +#endif +#if defined(IS_DARWIN) && __has_feature(ptrauth_qualifier) +// INTRIN_MAC: has_ptrauth_qualifier2 +void has_ptrauth_qualifier2() {} +#ifndef __PTRAUTH__ +#error ptrauth_qualifier extension present without predefined test macro +#endif +#endif +#if defined(__PTRAUTH__) +// INTRIN: has_ptrauth_qualifier3 +void has_ptrauth_qualifier3() {} +#endif + +#if !defined(__PTRAUTH__) && !__has_feature(ptrauth_qualifier) && !__has_extension(ptrauth_qualifier) // 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 a440791d6cc69..45d9cd4245dba 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -34,7 +34,7 @@ // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-elf-got | \ // RUN: FileCheck %s --check-prefixes=NOINTRIN,NOCALLS,NORETS,NOVPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,NOTYPE_INFO_DISCR,NOFUNC,NOINITFINI,NOINITFINI_ADDR_DISCR,NOGOTOS,ELFGOT -#if __has_feature(ptrauth_intrinsics) +#if defined(__PTRAUTH__) // INTRIN: has_ptrauth_intrinsics void has_ptrauth_intrinsics() {} #else diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c index 5d932b724f07a..3e568ce9f37e3 100644 --- a/clang/test/Sema/ptrauth-qualifier.c +++ b/clang/test/Sema/ptrauth-qualifier.c @@ -1,13 +1,25 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -std=c23 -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple arm64-apple-ios -DIS_DARWIN -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_extension(ptrauth_qualifier) +#if defined(IS_DARWIN) && !__has_extension(ptrauth_qualifier) // This error means that the __ptrauth qualifier availability test says that it // is not available. This error is not expected in the output, if it is seen // there is a feature detection regression. #error __ptrauth qualifier not enabled #endif +#if defined(IS_DARWIN) && !__has_feature(ptrauth_qualifier) +// This error means that the __has_feature test for ptrauth_qualifier has +// failed, despite it being expected on darwin. +#error __ptrauth qualifier not enabled +#elif !defined(IS_DARWIN) && (__has_feature(ptrauth_qualifier) || __has_extension(ptrauth_qualifier)) +#error ptrauth_qualifier labeled a feature on a non-darwin platform +#endif + +#if !defined (__PTRAUTH__) +#error __PTRAUTH__ test macro not defined when ptrauth is enabled +#endif + #if __aarch64__ #define VALID_CODE_KEY 0 #define VALID_DATA_KEY 2 diff --git a/clang/test/SemaObjC/ptrauth-qualifier.m b/clang/test/SemaObjC/ptrauth-qualifier.m index 74bbe6f09899b..67a73bbe45777 100644 --- a/clang/test/SemaObjC/ptrauth-qualifier.m +++ b/clang/test/SemaObjC/ptrauth-qualifier.m @@ -1,13 +1,25 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple arm64-apple-ios -DIS_DARWIN -fsyntax-only -verify -fptrauth-intrinsics %s // RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics %s -#if !__has_extension(ptrauth_qualifier) +#if defined(IS_DARWIN) && !__has_extension(ptrauth_qualifier) // This error means that the __ptrauth qualifier availability test says that it // is not available. This error is not expected in the output, if it is seen // there is a feature detection regression. #error __ptrauth qualifier not enabled #endif +#if defined(IS_DARWIN) && !__has_feature(ptrauth_qualifier) +// This error means that the __has_feature test for ptrauth_qualifier has +// failed, despite it being expected on darwin. +#error __ptrauth qualifier not enabled +#elif !defined(IS_DARWIN) && (__has_feature(ptrauth_qualifier) || __has_extension(ptrauth_qualifier)) +#error ptrauth_qualifier labeled a feature on a non-darwin platform +#endif + +#if !defined (__PTRAUTH__) +#error __PTRAUTH__ test macro not defined when ptrauth is 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}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits