[clang] [clang] Fix PointerAuth semantics of cpp_trivially_relocatable (PR #143969)
Oliver Hunt via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 14 21:22:04 PDT 2025
https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/143969
>From f47680310ed68a9f8e8cb15bc1cd474740072463 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Thu, 12 Jun 2025 13:17:11 -0700
Subject: [PATCH 1/3] [clang] Fix PointerAuth semantics of
cpp_trivially_relocatable
This adds a function to ASTContext to query whether a type contains
values with address discriminated pointer auth, and performs the
required semantic checks to ensure correct reporting of relocatablity
in those cases.
For the standardized version, __builtin_is_cpp_trivially_relocatable
this means rejecting unions of types containing address discriminated
values.
For the old deprecated __builtin_is_trivially_relocatable this means
rejecting any type containing an address discriminated value.
This PR does not update the codegen for __builtin_trivially_relocate,
that will be in a follow on PR that is much more complex.
---
clang/include/clang/AST/ASTContext.h | 4 +
clang/lib/AST/ASTContext.cpp | 49 +++++++++
clang/lib/Sema/SemaTypeTraits.cpp | 14 +--
.../SemaCXX/cxx2c-trivially-relocatable.cpp | 1 +
clang/test/SemaCXX/ptrauth-triviality.cpp | 10 +-
.../SemaCXX/trivially-relocatable-ptrauth.cpp | 102 ++++++++++++++++++
6 files changed, 169 insertions(+), 11 deletions(-)
create mode 100644 clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 8d24d393eab09..826f5257b0463 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -628,10 +628,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
getRelocationInfoForCXXRecord(const CXXRecordDecl *) const;
void setRelocationInfoForCXXRecord(const CXXRecordDecl *,
CXXRecordDeclRelocationInfo);
+ bool containsAddressDiscriminatedPointerAuth(QualType T);
private:
llvm::DenseMap<const CXXRecordDecl *, CXXRecordDeclRelocationInfo>
RelocatableClasses;
+ llvm::DenseMap<const RecordDecl *, bool>
+ RecordContainsAddressDiscriminatedPointerAuth;
ImportDecl *FirstLocalImport = nullptr;
ImportDecl *LastLocalImport = nullptr;
@@ -3668,6 +3671,7 @@ OPT_LIST(V)
/// authentication policy for the specified record.
const CXXRecordDecl *
baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
+ bool hasAddressDiscriminatedVTableAuthentication(const CXXRecordDecl *Class);
bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b51f7622288df..34b540fd36efc 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1705,6 +1705,40 @@ void ASTContext::setRelocationInfoForCXXRecord(
RelocatableClasses.insert({D, Info});
}
+bool ASTContext::containsAddressDiscriminatedPointerAuth(QualType T) {
+ if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIntrinsics)
+ return false;
+
+ T = T.getCanonicalType();
+ if (T.hasAddressDiscriminatedPointerAuth())
+ return true;
+ const RecordDecl *RD = T->getAsRecordDecl();
+ if (!RD)
+ return false;
+
+ auto SaveReturn = [this, RD](bool Result) {
+ RecordContainsAddressDiscriminatedPointerAuth.insert({RD, Result});
+ return Result;
+ };
+ if (auto Existing = RecordContainsAddressDiscriminatedPointerAuth.find(RD);
+ Existing != RecordContainsAddressDiscriminatedPointerAuth.end())
+ return Existing->second;
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ if (CXXRD->isPolymorphic() &&
+ hasAddressDiscriminatedVTableAuthentication(CXXRD))
+ return SaveReturn(true);
+ for (auto Base : CXXRD->bases()) {
+ if (containsAddressDiscriminatedPointerAuth(Base.getType()))
+ return SaveReturn(true);
+ }
+ }
+ for (auto *FieldDecl : RD->fields()) {
+ if (containsAddressDiscriminatedPointerAuth(FieldDecl->getType()))
+ return SaveReturn(true);
+ }
+ return SaveReturn(false);
+}
+
void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
assert(!Import->getNextLocalImport() &&
"Import declaration already in the chain");
@@ -15121,6 +15155,21 @@ ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
return PrimaryBase;
}
+bool ASTContext::hasAddressDiscriminatedVTableAuthentication(
+ const CXXRecordDecl *Class) {
+ assert(Class->isPolymorphic());
+ const CXXRecordDecl *BaseType = baseForVTableAuthentication(Class);
+ using AuthAttr = VTablePointerAuthenticationAttr;
+ const auto *ExplicitAuth = BaseType->getAttr<AuthAttr>();
+ if (!ExplicitAuth)
+ return LangOpts.PointerAuthVTPtrAddressDiscrimination;
+ AuthAttr::AddressDiscriminationMode AddressDiscrimination =
+ ExplicitAuth->getAddressDiscrimination();
+ if (AddressDiscrimination == AuthAttr::DefaultAddressDiscrimination)
+ return LangOpts.PointerAuthVTPtrAddressDiscrimination;
+ return AddressDiscrimination == AuthAttr::AddressDiscrimination;
+}
+
bool ASTContext::useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName) {
auto *Method = cast<CXXMethodDecl>(VirtualMethodDecl.getDecl());
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 1738ab4466001..43af236068655 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -188,15 +188,20 @@ static bool IsEligibleForTrivialRelocation(Sema &SemaRef,
return false;
}
+ bool IsUnion = D->isUnion();
for (const FieldDecl *Field : D->fields()) {
- if (Field->getType()->isDependentType())
+ QualType FieldType = Field->getType();
+ if (FieldType->isDependentType())
continue;
- if (Field->getType()->isReferenceType())
+ if (FieldType->isReferenceType())
continue;
// ... has a non-static data member of an object type that is not
// of a trivially relocatable type
if (!SemaRef.IsCXXTriviallyRelocatableType(Field->getType()))
return false;
+ if (IsUnion &&
+ SemaRef.Context.containsAddressDiscriminatedPointerAuth(FieldType))
+ return false;
}
return !D->hasDeletedDestructor();
}
@@ -322,9 +327,6 @@ bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
if (BaseElementType.hasNonTrivialObjCLifetime())
return false;
- if (BaseElementType.hasAddressDiscriminatedPointerAuth())
- return false;
-
if (BaseElementType->isIncompleteType())
return false;
@@ -670,7 +672,7 @@ static bool IsTriviallyRelocatableType(Sema &SemaRef, QualType T) {
if (!BaseElementType->isObjectType())
return false;
- if (T.hasAddressDiscriminatedPointerAuth())
+ if (SemaRef.getASTContext().containsAddressDiscriminatedPointerAuth(T))
return false;
if (const auto *RD = BaseElementType->getAsCXXRecordDecl();
diff --git a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp
index 9d43994ee7661..7152a5937d9b7 100644
--- a/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp
+++ b/clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++2c -verify %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-intrinsics -fptrauth-calls -std=c++2c -verify %s
class Trivial {};
static_assert(__builtin_is_cpp_trivially_relocatable(Trivial));
diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp b/clang/test/SemaCXX/ptrauth-triviality.cpp
index 60d1b57230f18..6f3650f7ac2e3 100644
--- a/clang/test/SemaCXX/ptrauth-triviality.cpp
+++ b/clang/test/SemaCXX/ptrauth-triviality.cpp
@@ -26,7 +26,7 @@ static_assert(!__is_trivially_assignable(S1, const S1&));
static_assert(__is_trivially_destructible(S1));
static_assert(!__is_trivially_copyable(S1));
static_assert(!__is_trivially_relocatable(S1)); // expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(S1));
+static_assert(__builtin_is_cpp_trivially_relocatable(S1));
static_assert(!__is_trivially_equality_comparable(S1));
static_assert(__is_trivially_constructible(Holder<S1>));
@@ -35,7 +35,7 @@ static_assert(!__is_trivially_assignable(Holder<S1>, const Holder<S1>&));
static_assert(__is_trivially_destructible(Holder<S1>));
static_assert(!__is_trivially_copyable(Holder<S1>));
static_assert(!__is_trivially_relocatable(Holder<S1>)); // expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(Holder<S1>));
+static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S1>));
static_assert(!__is_trivially_equality_comparable(Holder<S1>));
struct S2 {
@@ -83,7 +83,7 @@ static_assert(!__is_trivially_constructible(Holder<S3>, const Holder<S3>&));
static_assert(!__is_trivially_assignable(Holder<S3>, const Holder<S3>&));
static_assert(__is_trivially_destructible(Holder<S3>));
static_assert(!__is_trivially_copyable(Holder<S3>));
-static_assert(__is_trivially_relocatable(Holder<S3>)); // expected-warning{{deprecated}}
+static_assert(!__is_trivially_relocatable(Holder<S3>)); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S3>));
static_assert(!__is_trivially_equality_comparable(Holder<S3>));
@@ -148,7 +148,7 @@ static_assert(!__is_trivially_assignable(S6, const S6&));
static_assert(__is_trivially_destructible(S6));
static_assert(!__is_trivially_copyable(S6));
static_assert(!__is_trivially_relocatable(S6)); // expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(S6));
+static_assert(__builtin_is_cpp_trivially_relocatable(S6));
static_assert(!__is_trivially_equality_comparable(S6));
static_assert(__is_trivially_constructible(Holder<S6>));
@@ -157,7 +157,7 @@ static_assert(!__is_trivially_assignable(Holder<S6>, const Holder<S6>&));
static_assert(__is_trivially_destructible(Holder<S6>));
static_assert(!__is_trivially_copyable(Holder<S6>));
static_assert(!__is_trivially_relocatable(Holder<S6>)); // expected-warning{{deprecated}}
-static_assert(!__builtin_is_cpp_trivially_relocatable(Holder<S6>));
+static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S6>));
static_assert(!__is_trivially_equality_comparable(Holder<S6>));
struct S7 {
diff --git a/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp b/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp
new file mode 100644
index 0000000000000..29722fadd4d17
--- /dev/null
+++ b/clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 -triple arm64 -fptrauth-calls -fptrauth-intrinsics -std=c++26 -verify %s
+
+// This test intentionally does not enable the global address discrimination
+// of vtable pointers. This lets us configure them with different schemas
+// and verify that we're correctly tracking the existence of address discrimination
+
+// expected-no-diagnostics
+
+struct NonAddressDiscPtrauth {
+ void * __ptrauth(1, 0, 1234) p;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(NonAddressDiscPtrauth));
+
+struct AddressDiscPtrauth {
+ void * __ptrauth(1, 1, 1234) p;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(AddressDiscPtrauth));
+
+struct MultipleBaseClasses : NonAddressDiscPtrauth, AddressDiscPtrauth {
+
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(MultipleBaseClasses));
+
+struct MultipleMembers {
+ NonAddressDiscPtrauth field0;
+ AddressDiscPtrauth field1;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(MultipleMembers));
+
+struct UnionOfPtrauth {
+ union {
+ NonAddressDiscPtrauth field0;
+ AddressDiscPtrauth field1;
+ } u;
+};
+
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfPtrauth));
+
+struct [[clang::ptrauth_vtable_pointer(process_independent,address_discrimination,no_extra_discrimination)]] Polymorphic trivially_relocatable_if_eligible {
+ virtual ~Polymorphic();
+};
+
+struct Foo : Polymorphic {
+ Foo(const Foo&);
+ ~Foo();
+};
+
+
+static_assert(__builtin_is_cpp_trivially_relocatable(Polymorphic));
+
+struct [[clang::ptrauth_vtable_pointer(process_independent,no_address_discrimination,no_extra_discrimination)]] NonAddressDiscriminatedPolymorphic trivially_relocatable_if_eligible {
+ virtual ~NonAddressDiscriminatedPolymorphic();
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(NonAddressDiscriminatedPolymorphic));
+
+
+struct PolymorphicMembers {
+ Polymorphic field;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(PolymorphicMembers));
+
+struct UnionOfPolymorphic {
+ union trivially_relocatable_if_eligible {
+ Polymorphic p;
+ int i;
+ } u;
+};
+
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfPolymorphic));
+
+
+struct UnionOfNonAddressDiscriminatedPolymorphic {
+ union trivially_relocatable_if_eligible {
+ NonAddressDiscriminatedPolymorphic p;
+ int i;
+ } u;
+};
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfNonAddressDiscriminatedPolymorphic));
+
+struct UnionOfNonAddressDiscriminatedPtrauth {
+ union {
+ NonAddressDiscPtrauth p;
+ int i;
+ } u;
+};
+
+static_assert(__builtin_is_cpp_trivially_relocatable(UnionOfNonAddressDiscriminatedPtrauth));
+
+struct UnionOfAddressDisriminatedPtrauth {
+ union {
+ AddressDiscPtrauth p;
+ int i;
+ } u;
+};
+
+static_assert(!__builtin_is_cpp_trivially_relocatable(UnionOfAddressDisriminatedPtrauth));
>From 3190a524391c5f31f957ef369359b1f631c32e07 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Thu, 12 Jun 2025 17:23:41 -0700
Subject: [PATCH 2/3] Add comments and more tests
---
clang/include/clang/AST/ASTContext.h | 20 +++++++++++
clang/lib/AST/ASTContext.cpp | 14 ++++----
clang/lib/Sema/SemaTypeTraits.cpp | 16 +++++----
clang/test/SemaCXX/ptrauth-triviality.cpp | 42 ++++++++++++++++++++---
4 files changed, 76 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 826f5257b0463..68b8d67ab4828 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -628,11 +628,25 @@ class ASTContext : public RefCountedBase<ASTContext> {
getRelocationInfoForCXXRecord(const CXXRecordDecl *) const;
void setRelocationInfoForCXXRecord(const CXXRecordDecl *,
CXXRecordDeclRelocationInfo);
+
+ /// Examines a given type, and returns whether the T itself
+ /// is address discriminated, or any transitively embedded types
+ /// contain data that is address discriminated. This includes
+ /// implicitly authenticated values like vtable pointers, as well as
+ /// explicitly qualified fields.
bool containsAddressDiscriminatedPointerAuth(QualType T);
private:
+ // A simple helper function to short circuit pointer auth checks.
+ bool isPointerAuthenticationAvailable() const {
+ return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics ||
+ LangOpts.PointerAuthVTPtrAddressDiscrimination;
+ }
+
llvm::DenseMap<const CXXRecordDecl *, CXXRecordDeclRelocationInfo>
RelocatableClasses;
+
+ // FIXME: store in RecordDeclBitfields in future?
llvm::DenseMap<const RecordDecl *, bool>
RecordContainsAddressDiscriminatedPointerAuth;
@@ -3671,7 +3685,13 @@ OPT_LIST(V)
/// authentication policy for the specified record.
const CXXRecordDecl *
baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
+
+ /// If this class is polymorphic, returns true if any of this class's
+ /// vtable pointers have an address discriminated pointer authentication
+ /// schema.
+ /// This does not check fields of the class or base classes.
bool hasAddressDiscriminatedVTableAuthentication(const CXXRecordDecl *Class);
+
bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 34b540fd36efc..6db95ac106703 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1706,7 +1706,7 @@ void ASTContext::setRelocationInfoForCXXRecord(
}
bool ASTContext::containsAddressDiscriminatedPointerAuth(QualType T) {
- if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIntrinsics)
+ if (!isPointerAuthenticationAvailable())
return false;
T = T.getCanonicalType();
@@ -1716,13 +1716,14 @@ bool ASTContext::containsAddressDiscriminatedPointerAuth(QualType T) {
if (!RD)
return false;
+ if (auto Existing = RecordContainsAddressDiscriminatedPointerAuth.find(RD);
+ Existing != RecordContainsAddressDiscriminatedPointerAuth.end())
+ return Existing->second;
+
auto SaveReturn = [this, RD](bool Result) {
RecordContainsAddressDiscriminatedPointerAuth.insert({RD, Result});
return Result;
};
- if (auto Existing = RecordContainsAddressDiscriminatedPointerAuth.find(RD);
- Existing != RecordContainsAddressDiscriminatedPointerAuth.end())
- return Existing->second;
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
if (CXXRD->isPolymorphic() &&
hasAddressDiscriminatedVTableAuthentication(CXXRD))
@@ -15157,10 +15158,11 @@ ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
bool ASTContext::hasAddressDiscriminatedVTableAuthentication(
const CXXRecordDecl *Class) {
- assert(Class->isPolymorphic());
+ if (!isPointerAuthenticationAvailable() || !Class->isPolymorphic())
+ return false;
const CXXRecordDecl *BaseType = baseForVTableAuthentication(Class);
using AuthAttr = VTablePointerAuthenticationAttr;
- const auto *ExplicitAuth = BaseType->getAttr<AuthAttr>();
+ const AuthAttr *ExplicitAuth = BaseType->getAttr<AuthAttr>();
if (!ExplicitAuth)
return LangOpts.PointerAuthVTPtrAddressDiscrimination;
AuthAttr::AddressDiscriminationMode AddressDiscrimination =
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 43af236068655..a0b989fc33b2a 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -190,17 +190,19 @@ static bool IsEligibleForTrivialRelocation(Sema &SemaRef,
bool IsUnion = D->isUnion();
for (const FieldDecl *Field : D->fields()) {
- QualType FieldType = Field->getType();
- if (FieldType->isDependentType())
+ if (Field->getType()->isDependentType())
continue;
- if (FieldType->isReferenceType())
+ if (Field->getType()->isReferenceType())
continue;
// ... has a non-static data member of an object type that is not
// of a trivially relocatable type
if (!SemaRef.IsCXXTriviallyRelocatableType(Field->getType()))
return false;
- if (IsUnion &&
- SemaRef.Context.containsAddressDiscriminatedPointerAuth(FieldType))
+
+ // A union contains values with address discriminated pointer auth
+ // cannot be relocated.
+ if (IsUnion && SemaRef.Context.containsAddressDiscriminatedPointerAuth(
+ Field->getType()))
return false;
}
return !D->hasDeletedDestructor();
@@ -318,7 +320,6 @@ bool Sema::IsCXXTriviallyRelocatableType(const CXXRecordDecl &RD) {
}
bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
-
QualType BaseElementType = getASTContext().getBaseElementType(Type);
if (Type->isVariableArrayType())
@@ -672,6 +673,9 @@ static bool IsTriviallyRelocatableType(Sema &SemaRef, QualType T) {
if (!BaseElementType->isObjectType())
return false;
+ // The deprecated __builtin_is_trivially_relocatable does not have
+ // an equivalent to __builtin_trivially_relocate, so there is no
+ // safe way to use it if there are any address discriminated values.
if (SemaRef.getASTContext().containsAddressDiscriminatedPointerAuth(T))
return false;
diff --git a/clang/test/SemaCXX/ptrauth-triviality.cpp b/clang/test/SemaCXX/ptrauth-triviality.cpp
index 6f3650f7ac2e3..2c95e93239790 100644
--- a/clang/test/SemaCXX/ptrauth-triviality.cpp
+++ b/clang/test/SemaCXX/ptrauth-triviality.cpp
@@ -1,5 +1,5 @@
-// 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
+// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++26 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++26 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s
#define AQ __ptrauth(1,1,50)
#define IQ __ptrauth(1,0,50)
@@ -99,7 +99,6 @@ static_assert(!__is_trivially_assignable(S4, const S4&));
static_assert(__is_trivially_destructible(S4));
static_assert(!__is_trivially_copyable(S4));
static_assert(!__is_trivially_relocatable(S4)); // expected-warning{{deprecated}}
-//FIXME
static_assert(__builtin_is_cpp_trivially_relocatable(S4));
static_assert(!__is_trivially_equality_comparable(S4));
@@ -124,7 +123,6 @@ static_assert(!__is_trivially_assignable(S5, const S5&));
static_assert(__is_trivially_destructible(S5));
static_assert(!__is_trivially_copyable(S5));
static_assert(!__is_trivially_relocatable(S5)); // expected-warning{{deprecated}}
-//FIXME
static_assert(__builtin_is_cpp_trivially_relocatable(S5));
static_assert(!__is_trivially_equality_comparable(S5));
@@ -182,3 +180,39 @@ static_assert(__is_trivially_copyable(Holder<S7>));
static_assert(__is_trivially_relocatable(Holder<S7>)); // expected-warning{{deprecated}}
static_assert(__builtin_is_cpp_trivially_relocatable(Holder<S7>));
static_assert(__is_trivially_equality_comparable(Holder<S7>));
+
+template <class... Bases> struct MultipleInheriter : Bases... {
+};
+
+template <class T> static const bool test_is_trivially_relocatable_v = __builtin_is_cpp_trivially_relocatable(T);
+template <class... Types> static const bool multiple_inheritance_is_relocatable = test_is_trivially_relocatable_v<MultipleInheriter<Types...>>;
+template <class... Types> static const bool inheritance_relocatability_matches_bases_v =
+ (test_is_trivially_relocatable_v<Types> && ...) == multiple_inheritance_is_relocatable<Types...>;
+
+static_assert(multiple_inheritance_is_relocatable<S4, S5> == multiple_inheritance_is_relocatable<S5, S4>);
+static_assert(inheritance_relocatability_matches_bases_v<S4, S5>);
+static_assert(inheritance_relocatability_matches_bases_v<S5, S4>);
+
+struct AA AddressDiscriminatedPolymorphicBase trivially_relocatable_if_eligible {
+ virtual void foo();
+};
+
+struct IA NoAddressDiscriminatedPolymorphicBase trivially_relocatable_if_eligible {
+ virtual void bar();
+};
+
+template <class T> struct UnionWrapper trivially_relocatable_if_eligible {
+ union U {
+ T field1;
+ } u;
+};
+
+static_assert(test_is_trivially_relocatable_v<AddressDiscriminatedPolymorphicBase>);
+static_assert(test_is_trivially_relocatable_v<NoAddressDiscriminatedPolymorphicBase>);
+static_assert(inheritance_relocatability_matches_bases_v<AddressDiscriminatedPolymorphicBase, NoAddressDiscriminatedPolymorphicBase>);
+static_assert(inheritance_relocatability_matches_bases_v<NoAddressDiscriminatedPolymorphicBase, AddressDiscriminatedPolymorphicBase>);
+
+static_assert(!test_is_trivially_relocatable_v<UnionWrapper<AddressDiscriminatedPolymorphicBase>>);
+static_assert(test_is_trivially_relocatable_v<UnionWrapper<NoAddressDiscriminatedPolymorphicBase>>);
+static_assert(!test_is_trivially_relocatable_v<UnionWrapper<MultipleInheriter<NoAddressDiscriminatedPolymorphicBase, AddressDiscriminatedPolymorphicBase>>>);
+static_assert(!test_is_trivially_relocatable_v<UnionWrapper<MultipleInheriter<AddressDiscriminatedPolymorphicBase, NoAddressDiscriminatedPolymorphicBase>>>);
>From 15b1a8136f7308c0f205a756a68f147208a36278 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sun, 15 Jun 2025 07:20:47 +0300
Subject: [PATCH 3/3] Address corentin comments
---
clang/include/clang/AST/ASTContext.h | 10 ++------
clang/lib/AST/ASTContext.cpp | 38 +++++++++++++++-------------
2 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 68b8d67ab4828..72e4d803289b4 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -635,14 +635,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// implicitly authenticated values like vtable pointers, as well as
/// explicitly qualified fields.
bool containsAddressDiscriminatedPointerAuth(QualType T);
-
-private:
// A simple helper function to short circuit pointer auth checks.
+
bool isPointerAuthenticationAvailable() const {
return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics ||
LangOpts.PointerAuthVTPtrAddressDiscrimination;
}
+private:
llvm::DenseMap<const CXXRecordDecl *, CXXRecordDeclRelocationInfo>
RelocatableClasses;
@@ -3686,12 +3686,6 @@ OPT_LIST(V)
const CXXRecordDecl *
baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
- /// If this class is polymorphic, returns true if any of this class's
- /// vtable pointers have an address discriminated pointer authentication
- /// schema.
- /// This does not check fields of the class or base classes.
- bool hasAddressDiscriminatedVTableAuthentication(const CXXRecordDecl *Class);
-
bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 6db95ac106703..76453b20f30a4 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1704,6 +1704,22 @@ void ASTContext::setRelocationInfoForCXXRecord(
assert(RelocatableClasses.find(D) == RelocatableClasses.end());
RelocatableClasses.insert({D, Info});
}
+static bool
+hasAddressDiscriminatedVTableAuthentication(ASTContext &Context,
+ const CXXRecordDecl *Class) {
+ if (!Context.isPointerAuthenticationAvailable() || !Class->isPolymorphic())
+ return false;
+ const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class);
+ using AuthAttr = VTablePointerAuthenticationAttr;
+ const AuthAttr *ExplicitAuth = BaseType->getAttr<AuthAttr>();
+ if (!ExplicitAuth)
+ return Context.getLangOpts().PointerAuthVTPtrAddressDiscrimination;
+ AuthAttr::AddressDiscriminationMode AddressDiscrimination =
+ ExplicitAuth->getAddressDiscrimination();
+ if (AddressDiscrimination == AuthAttr::DefaultAddressDiscrimination)
+ return Context.getLangOpts().PointerAuthVTPtrAddressDiscrimination;
+ return AddressDiscrimination == AuthAttr::AddressDiscrimination;
+}
bool ASTContext::containsAddressDiscriminatedPointerAuth(QualType T) {
if (!isPointerAuthenticationAvailable())
@@ -1721,12 +1737,14 @@ bool ASTContext::containsAddressDiscriminatedPointerAuth(QualType T) {
return Existing->second;
auto SaveReturn = [this, RD](bool Result) {
- RecordContainsAddressDiscriminatedPointerAuth.insert({RD, Result});
+ auto __unused[ResultIter, DidAdd] =
+ RecordContainsAddressDiscriminatedPointerAuth.try_emplace(RD, Result);
+ assert(DidAdd);
return Result;
};
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
if (CXXRD->isPolymorphic() &&
- hasAddressDiscriminatedVTableAuthentication(CXXRD))
+ hasAddressDiscriminatedVTableAuthentication(*this, CXXRD))
return SaveReturn(true);
for (auto Base : CXXRD->bases()) {
if (containsAddressDiscriminatedPointerAuth(Base.getType()))
@@ -15156,22 +15174,6 @@ ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
return PrimaryBase;
}
-bool ASTContext::hasAddressDiscriminatedVTableAuthentication(
- const CXXRecordDecl *Class) {
- if (!isPointerAuthenticationAvailable() || !Class->isPolymorphic())
- return false;
- const CXXRecordDecl *BaseType = baseForVTableAuthentication(Class);
- using AuthAttr = VTablePointerAuthenticationAttr;
- const AuthAttr *ExplicitAuth = BaseType->getAttr<AuthAttr>();
- if (!ExplicitAuth)
- return LangOpts.PointerAuthVTPtrAddressDiscrimination;
- AuthAttr::AddressDiscriminationMode AddressDiscrimination =
- ExplicitAuth->getAddressDiscrimination();
- if (AddressDiscrimination == AuthAttr::DefaultAddressDiscrimination)
- return LangOpts.PointerAuthVTPtrAddressDiscrimination;
- return AddressDiscrimination == AuthAttr::AddressDiscrimination;
-}
-
bool ASTContext::useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName) {
auto *Method = cast<CXXMethodDecl>(VirtualMethodDecl.getDecl());
More information about the cfe-commits
mailing list