[clang] WIP warning (PR #172186)
Oliver Hunt via cfe-commits
cfe-commits at lists.llvm.org
Sat Dec 13 16:02:03 PST 2025
https://github.com/ojhunt created https://github.com/llvm/llvm-project/pull/172186
None
>From 7c547005228cdb185fc0f5458c62d0c24e2df9b6 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sat, 13 Dec 2025 00:39:04 -0800
Subject: [PATCH 1/2] start refactoring the ptrauth thingy
---
clang/include/clang/AST/ASTContext.h | 28 +++++++++++------
clang/include/clang/Basic/DiagnosticGroups.td | 1 +
.../clang/Basic/DiagnosticSemaKinds.td | 3 ++
clang/lib/AST/ASTContext.cpp | 31 ++++++++++---------
4 files changed, 39 insertions(+), 24 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index f64e29be3205f..271fb831406fb 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -681,7 +681,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool containsAddressDiscriminatedPointerAuth(QualType T) const {
if (!isPointerAuthenticationAvailable())
return false;
- return findPointerAuthContent(T) != PointerAuthContent::None;
+ return (findPointerAuthContent(T) & PointerAuthContent::ContainsAddressDiscriminatedData) != PointerAuthContent::ContainsNone;
}
/// Examines a given type, and returns whether the type itself
@@ -692,7 +692,18 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool containsNonRelocatablePointerAuth(QualType T) {
if (!isPointerAuthenticationAvailable())
return false;
- return findPointerAuthContent(T) != PointerAuthContent::None;
+ return (findPointerAuthContent(T) & PointerAuthContent::ContainsAddressDiscriminatedData) != PointerAuthContent::ContainsNone;
+ }
+
+ bool containsDefaultAuthenticatedFunctionPointer(QualType T) {
+ if (!isPointerAuthenticationAvailable())
+ return false;
+ return (findPointerAuthContent(T) & PointerAuthContent::ContainsDefaultAuthenticatedFunction) != PointerAuthContent::ContainsNone;
+ }
+
+ // A simple helper function to short circuit pointer auth checks.
+ bool isPointerAuthenticationAvailable() const {
+ return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics;
}
private:
@@ -701,15 +712,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
// FIXME: store in RecordDeclBitfields in future?
enum class PointerAuthContent : uint8_t {
- None,
- AddressDiscriminatedVTable,
- AddressDiscriminatedData
+ ContainsNone = 0,
+ ContainsAddressDiscriminatedVTable = 1 << 0,
+ ContainsAddressDiscriminatedData = 1 << 1,
+ ContainsDefaultAuthenticatedFunction = 1 << 2,
+ ContainsAllFlags = ContainsAddressDiscriminatedVTable | ContainsAddressDiscriminatedData | ContainsDefaultAuthenticatedFunction,
+ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ContainsDefaultAuthenticatedFunction)
};
- // A simple helper function to short circuit pointer auth checks.
- bool isPointerAuthenticationAvailable() const {
- return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics;
- }
PointerAuthContent findPointerAuthContent(QualType T) const;
mutable llvm::DenseMap<const RecordDecl *, PointerAuthContent>
RecordContainsAddressDiscriminatedPointerAuth;
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index e1dba0195f470..16434f9f9dd46 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1081,6 +1081,7 @@ def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments", [VariadicMacroArgumentsOmitted]>;
def MisleadingIndentation : DiagGroup<"misleading-indentation">;
def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">;
+def PtrAuthWeakSchema : DiagGroup<"ptrauth-weak-schema">;
// This covers both the deprecated case (in C++98)
// and the extension case (in C++11 onwards).
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 381d1fb063eba..46cfdf85e504a 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1018,6 +1018,9 @@ def err_ptrauth_string_not_literal : Error<
def err_ptrauth_type_disc_undiscriminated : Error<
"cannot pass undiscriminated type %0 to "
"'__builtin_ptrauth_type_discriminator'">;
+def warn_ptrauth_weak_global_function_pointer :
+ Warning<"global pointer %0 uses the default pointer authentication schema">,
+ InGroup<PtrAuthWeakSchema>;
def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
Note<"cannot take an address of a virtual member function if its return or "
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index f4aadeceb4bb7..e1e6f5015cf68 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1640,23 +1640,27 @@ ASTContext::findPointerAuthContent(QualType T) const {
T = T.getCanonicalType();
if (T->isDependentType())
- return PointerAuthContent::None;
+ return PointerAuthContent::ContainsNone;
+ PointerAuthContent Result = PointerAuthContent::ContainsNone;
if (T.hasAddressDiscriminatedPointerAuth())
- return PointerAuthContent::AddressDiscriminatedData;
+ Result = Result | PointerAuthContent::ContainsAddressDiscriminatedData;
+ if (T->isFunctionPointerType()) {
+ PointerAuthQualifier ExplicitQualifier = T.getPointerAuth();
+ if (!ExplicitQualifier.isPresent() || !ExplicitQualifier.isAddressDiscriminated())
+ Result = Result | PointerAuthContent::ContainsDefaultAuthenticatedFunction;
+ }
const RecordDecl *RD = T->getAsRecordDecl();
if (!RD)
- return PointerAuthContent::None;
+ return Result;
if (RD->isInvalidDecl())
- return PointerAuthContent::None;
+ return PointerAuthContent::ContainsNone;
if (auto Existing = RecordContainsAddressDiscriminatedPointerAuth.find(RD);
Existing != RecordContainsAddressDiscriminatedPointerAuth.end())
return Existing->second;
- PointerAuthContent Result = PointerAuthContent::None;
-
auto SaveResultAndReturn = [&]() -> PointerAuthContent {
auto [ResultIter, DidAdd] =
RecordContainsAddressDiscriminatedPointerAuth.try_emplace(RD, Result);
@@ -1665,19 +1669,16 @@ ASTContext::findPointerAuthContent(QualType T) const {
assert(DidAdd);
return Result;
};
- auto ShouldContinueAfterUpdate = [&](PointerAuthContent NewResult) {
- static_assert(PointerAuthContent::None <
- PointerAuthContent::AddressDiscriminatedVTable);
- static_assert(PointerAuthContent::AddressDiscriminatedVTable <
- PointerAuthContent::AddressDiscriminatedData);
- if (NewResult > Result)
- Result = NewResult;
- return Result != PointerAuthContent::AddressDiscriminatedData;
+ auto ShouldContinueAfterUpdate = [&](PointerAuthContent NewFlag) {
+ Result = Result | NewFlag;
+ if ((NewFlag & PointerAuthContent::ContainsAddressDiscriminatedVTable) != PointerAuthContent::ContainsNone)
+ Result = Result | PointerAuthContent::ContainsAddressDiscriminatedData;
+ return Result != PointerAuthContent::ContainsAllFlags;
};
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
if (primaryBaseHaseAddressDiscriminatedVTableAuthentication(*this, CXXRD) &&
!ShouldContinueAfterUpdate(
- PointerAuthContent::AddressDiscriminatedVTable))
+ PointerAuthContent::ContainsAddressDiscriminatedVTable))
return SaveResultAndReturn();
for (auto Base : CXXRD->bases()) {
if (!ShouldContinueAfterUpdate(findPointerAuthContent(Base.getType())))
>From d1069b81869e1c49e3dc2ea0a2fcd3ce37843f66 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sat, 13 Dec 2025 15:27:24 -0800
Subject: [PATCH 2/2] not to be actually merged but want to keep the tests
handy
---
clang/include/clang/Basic/DiagnosticGroups.td | 2 +-
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/Sema.cpp | 5 +++++
clang/lib/Sema/SemaDecl.cpp | 7 +++++++
clang/test/SemaCXX/ptrauth-type-traits.cpp | 10 +++++++++-
5 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 16434f9f9dd46..7a9aa80a48148 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1081,7 +1081,7 @@ def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments", [VariadicMacroArgumentsOmitted]>;
def MisleadingIndentation : DiagGroup<"misleading-indentation">;
def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">;
-def PtrAuthWeakSchema : DiagGroup<"ptrauth-weak-schema">;
+def PtrAuthWeakGlobalSchema : DiagGroup<"ptrauth-weak-global-schema">;
// This covers both the deprecated case (in C++98)
// and the extension case (in C++11 onwards).
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 46cfdf85e504a..c5326cf3cf717 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1019,7 +1019,7 @@ def err_ptrauth_type_disc_undiscriminated : Error<
"cannot pass undiscriminated type %0 to "
"'__builtin_ptrauth_type_discriminator'">;
def warn_ptrauth_weak_global_function_pointer :
- Warning<"global pointer %0 uses the default pointer authentication schema">,
+ Warning<"global variable %0 uses the default pointer authentication schema">,
InGroup<PtrAuthWeakSchema>;
def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index d32d7b960288d..dabcd1596252f 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -994,6 +994,10 @@ void Sema::getUndefinedButUsed(
}
}
+static void checkQuestionableGlobalFunctionPointers(Sema &S) {
+
+}
+
/// checkUndefinedButUsed - Check for undefined objects with internal linkage
/// or that are inline.
static void checkUndefinedButUsed(Sema &S) {
@@ -1624,6 +1628,7 @@ void Sema::ActOnEndOfTranslationUnit() {
TUScope = nullptr;
checkExposure(Context.getTranslationUnitDecl());
+ checkQuestionableGlobalFunctionPointers(*this);
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 47bd7295e93f6..051245630f854 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15053,6 +15053,13 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Build the bindings if this is a structured binding declaration.
if (auto *DD = dyn_cast<DecompositionDecl>(var))
CheckCompleteDecompositionDeclaration(DD);
+
+ if (GlobalStorage && Context.isPointerAuthenticationAvailable() &&
+ !Diags.isIgnored(diag::warn_ptrauth_weak_global_function_pointer, var->getLocation())) {
+ if (Context.containsDefaultAuthenticatedFunctionPointer(var->getType())) {
+ Diag(var->getLocation(), diag::warn_ptrauth_weak_global_function_pointer) << var << var->getSourceRange();
+ }
+ }
}
void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
diff --git a/clang/test/SemaCXX/ptrauth-type-traits.cpp b/clang/test/SemaCXX/ptrauth-type-traits.cpp
index a81ef1cce25b6..f4e33802e36f8 100644
--- a/clang/test/SemaCXX/ptrauth-type-traits.cpp
+++ b/clang/test/SemaCXX/ptrauth-type-traits.cpp
@@ -427,7 +427,15 @@ namespace GH159505 {
static_assert(PTRAUTH_ENABLED != __is_trivially_copyable(Ptr<T>));
}
- auto f = test<int>;
+ auto * __ptrauth(1,1,1) f = test<int>;
+ void (*__ptrauth(1,0,0) f1)() = test<int>;
+ void (*__ptrauth(1,1,0) f2)() = test<int>;
+ void (*__ptrauth(1,1,1) f3)() = test<int>;
+
+ struct Foo {
+ void (*field)();
+ };
+ Foo object;
static_assert(!__is_trivially_copyable(B<1>));
static_assert(PTRAUTH_ENABLED != __is_trivially_copyable(C<1>));
More information about the cfe-commits
mailing list