Skip to content

[clang][PAC] ptrauth_qualifier must be considered a feature #153291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ojhunt
Copy link
Contributor

@ojhunt ojhunt commented Aug 12, 2025

During the upstreaming process the ptrauth qualifier test was changed from a feature
test to an extension test. Unfortunately under pedantic-errors this results in the
ptrauth qualifier being reported as disabled. As the ptrauth qualifier impacts the ABI
this is not sound, so this PR returns the ptrauth qualifier to being detected through a
feature check.

…sion

Under `-pedantic-errors` extensions (as detected by __has_extension) are
not enabled (or rather the tests return false). As the ptrauth qualifier
impacts the ABI this is not sound, so this PR returns the ptrauth qualifier
to being detected through a feature check.
@ojhunt ojhunt self-assigned this Aug 12, 2025
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 12, 2025
@ojhunt ojhunt added this to the LLVM 21.x Release milestone Aug 12, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in LLVM Release Status Aug 12, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 12, 2025

@llvm/pr-subscribers-clang

Author: Oliver Hunt (ojhunt)

Changes

During the upstreaming process the ptrauth qualifier test was changed from a feature
test to an extension test. Unfortunately under pedantic-errors this results in the
ptrauth qualifier being reported as disabled. As the ptrauth qualifier impacts the ABI
this is not sound, so this PR returns the ptrauth qualifier to being detected through a
feature check.


Full diff: https://github.com/llvm/llvm-project/pull/153291.diff

4 Files Affected:

  • (modified) clang/include/clang/Basic/Features.def (+1-1)
  • (modified) clang/test/Preprocessor/ptrauth_extension.c (+7-1)
  • (modified) clang/test/Sema/ptrauth-qualifier.c (+6-1)
  • (modified) clang/test/SemaObjC/ptrauth-qualifier.m (+2-1)
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index c58e3f2400adc..404ae9e1fca14 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -148,7 +148,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)
-EXTENSION(ptrauth_qualifier, 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/test/Preprocessor/ptrauth_extension.c b/clang/test/Preprocessor/ptrauth_extension.c
index d6b79187ba62d..5a0fbaa9e0e2d 100644
--- a/clang/test/Preprocessor/ptrauth_extension.c
+++ b/clang/test/Preprocessor/ptrauth_extension.c
@@ -1,10 +1,16 @@
 // RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-intrinsics | \
 // RUN:   FileCheck %s --check-prefixes=INTRIN
 
+// RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-intrinsics -pedantic-errors | \
+// 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)
+// RUN: %clang_cc1 -E %s -triple=aarch64 -fptrauth-calls -pedantic-errors | \
+// RUN:   FileCheck %s --check-prefixes=NOINTRIN
+
+#if __has_feature(ptrauth_qualifier)
 // INTRIN: has_ptrauth_qualifier
 void has_ptrauth_qualifier() {}
 #else
diff --git a/clang/test/Sema/ptrauth-qualifier.c b/clang/test/Sema/ptrauth-qualifier.c
index 5d932b724f07a..18fada51bcbbe 100644
--- a/clang/test/Sema/ptrauth-qualifier.c
+++ b/clang/test/Sema/ptrauth-qualifier.c
@@ -1,7 +1,8 @@
 // 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
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c23 -fsyntax-only -verify -fptrauth-intrinsics -pedantic-errors -DPEDANTIC_ERRORS %s
 
-#if !__has_extension(ptrauth_qualifier)
+#if !__has_feature(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.
@@ -66,6 +67,7 @@ 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)')}}
 
+#ifndef PEDANTIC_ERRORS
 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));
@@ -73,6 +75,7 @@ static_assert(_Generic(valid0, int * __ptrauth(VALID_DATA_KEY) : 0, int * : 1, d
 
 static_assert(_Generic(array0, int * __ptrauth(VALID_DATA_KEY) * : 1, default : 0));
 static_assert(_Generic(*array1, int * : 1, default : 0));
+#endif
 
 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)')}}
@@ -99,8 +102,10 @@ void test_array(void) {
 __attribute__((overloadable)) int overload_func(int **);
 __attribute__((overloadable)) float overload_func(int * __ptrauth(VALID_DATA_KEY) *);
 
+#ifndef PEDANTIC_ERRORS
 static_assert(_Generic(typeof(overload_func(&ptr0)), int : 1, default : 0));
 static_assert(_Generic(typeof(overload_func(&valid0)), float : 1, default : 0));
+#endif
 
 void func(int array[__ptrauth(VALID_DATA_KEY) 10]); // expected-error {{'__ptrauth' qualifier only applies to pointer or pointer sized integer types; 'int[10]' is invalid}}
 
diff --git a/clang/test/SemaObjC/ptrauth-qualifier.m b/clang/test/SemaObjC/ptrauth-qualifier.m
index 74bbe6f09899b..bd64dc85d21a5 100644
--- a/clang/test/SemaObjC/ptrauth-qualifier.m
+++ b/clang/test/SemaObjC/ptrauth-qualifier.m
@@ -1,7 +1,8 @@
 // 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 aarch64-linux-gnu -fsyntax-only -verify -fptrauth-intrinsics -pedantic-errors %s
 
-#if !__has_extension(ptrauth_qualifier)
+#if !__has_feature(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.

ojhunt added a commit that referenced this pull request Aug 13, 2025
Also update to __has_feature, though that is blocked on #153291
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, ptrauth is not a feature, it is an extension and should be reported as such. The real bug here is that you're missing an extension warning when __ptrauth is used: https://godbolt.org/z/4Mb8f4W94

That code needs to issue an extension warning.

@ojhunt
Copy link
Contributor Author

ojhunt commented Aug 13, 2025

No, ptrauth is not a feature, it is an extension and should be reported as such. The real bug here is that you're missing an extension warning when __ptrauth is used: https://godbolt.org/z/4Mb8f4W94

That code needs to issue an extension warning.

That means all code targeting arm64e/armv8.3 would produce this warning. Pointer authentication is platform ABI, so this warning would be present in every build (if nothing else due to system headers) and as a result would be disabled anyway, rendering it moot.

Then because -pedantic-errors now breaks the platform ABI, using that flag would be required to be a compile time error.

I understand that the semantics of __has_extension might better match the mental model of the __ptrauth qualifier on platforms that do not support pointer auth, but on platforms where it is part of the abi it is not an extension, it's a core part of the platform and can never be ignored.

The ODR violation argument doesn't really help: by virtue of breaking the ability to detect support for the qualifier code cannot match the ABI without requiring an external check followed by a macro define that they can test on instead, but that is not an option for the ABI definitions as a system headers can't rely on that, so -pedantic-errors breaks the ABI and causes ODR violations.

i.e by requiring the ptrauth qualifier be an extension:

  • All code on these platforms will produce a "you're using an extension" warning, so either it gets a separate warning from the standard extension warning, which would then be disabled on all code (realistically it would be implicitly disabled for these targets), or the general "you are using an extension warning" would have to be disabled.
  • When targeting platforms with pointer authentication attempting to use -pedantic-errors (or any other flag impacting the behavior of __has_extension) would be a hard error at compile time.

That would be the behavior in the llvm.org tree, every platform that supports pointer auth would in all likelihood patch this into a feature to avoid these problems: breaking code that uses -pedantic-errors isn't acceptable, and neither is producing warnings in all code targeting that platform, especially given those warnings would quite literally be a warning about the target: user chooses to target a platform that requires pointer authentication, code compiles and produces a warning that they are targeting a platform that uses pointer authentication. All code compiling with -Werror then also needs to add -Wno- to disable the warning that they are compiling to the target they have chosen to target.

@efriedma-quic
Copy link
Collaborator

No, ptrauth is not a feature, it is an extension and should be reported as such. The real bug here is that you're missing an extension warning when __ptrauth is used

I thought our general policy was that we don't trigger pedantic warnings for reserved keywords (like anything with a __ prefix)?

@ojhunt
Copy link
Contributor Author

ojhunt commented Aug 13, 2025

No, ptrauth is not a feature, it is an extension and should be reported as such. The real bug here is that you're missing an extension warning when __ptrauth is used

I thought our general policy was that we don't trigger pedantic warnings for reserved keywords (like anything with a __ prefix)?

the problem is that __has_extension simply reports false on anything marked as an extension, so feature checks performed via __has_extension stop working.

The more I think about this the more weird the behavior is - you can still use the extensions (I think you can simply suppress the warnings for the cases where extensions do actually produce them), you just can't check for them :-/

An alternative approach - that would require significant code updates - would be to blast down a pile of implicit macros for all the current feature tests, which would at least provide a non-__has_extension based approach for testing. Obviously this will require a pile of work and testing and basically end up with a lot of __has_feature(...) || defined(feature macro) but that would resolve the __has_extension problem.

Failing that we could add a flag to the internal extension model so that some extensions will return the correct value even if -pedantic-errors is set.

@ojhunt
Copy link
Contributor Author

ojhunt commented Aug 13, 2025

Right, so in macro expansion we have

  // If the use of an extension results in an error diagnostic, extensions are
  // effectively unavailable, so just return false here.
  if (PP.getDiagnostics().getExtensionHandlingBehavior() >=
      diag::Severity::Error)
    return false;

But if you have -Wno-<some-extension-warning> the use of the extension would in principle not generate an warning, and so this would be "ok" and this path should not have been taken.

@ojhunt
Copy link
Contributor Author

ojhunt commented Aug 13, 2025

*that said this behavior does match gcc's :-/

@efriedma-quic
Copy link
Collaborator

Can we just drop the check from __has_extension handling?

It looks like that check dates back to the introduction of __has_extension (d5d410f). But it's a terrible idea for a lot of reasons: it adds a semantic effect to a flag which otherwise doesn't have any semantic effects, and even for extensions that are actually extensions, there are plenty of ways to suppress the diagnostic even in pedantic-errors mode.

(And as a practical matter, some large fraction of codebases that care about pedantic warnings probably use -Werror -pedantic, which doesn't have this effect, so it's not like we were even being consistent here.)

@ojhunt
Copy link
Contributor Author

ojhunt commented Aug 13, 2025

Can we just drop the check from __has_extension handling?

It looks like that check dates back to the introduction of __has_extension (d5d410f). But it's a terrible idea for a lot of reasons: it adds a semantic effect to a flag which otherwise doesn't have any semantic effects, and even for extensions that are actually extensions, there are plenty of ways to suppress the diagnostic even in pedantic-errors mode.

(And as a practical matter, some large fraction of codebases that care about pedantic warnings probably use -Werror -pedantic, which doesn't have this effect, so it's not like we were even being consistent here.)

Yeah, that's what I was thinking -- it honestly feels like an optimization that may have been inherited from gcc if that came first, but the optimization is based on an assumption that all use of any extensions will produce a warning that gets promoted to an error which is not accurate.

I would be concerned about changing this specific behavior for llvm21 though, but I have an idea for a more targeted change

@ojhunt
Copy link
Contributor Author

ojhunt commented Aug 13, 2025

@efriedma-quic @AaronBallman I just posted a proof of concept version of a restricted "__has_extension that works under -pedantic-errors" : #153506

(Side note, it might be nice to be able to create a way to deprecate __has_feature tests so that code using __has_feature can be warned and migrate to __has_extension)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
Status: Needs Triage
Development

Successfully merging this pull request may close these issues.

4 participants