Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
49 changes: 49 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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});
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
RecordContainsAddressDiscriminatedPointerAuth.insert({RD, Result});
RecordContainsAddressDiscriminatedPointerAuth.emplace(RD, Result);

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you move SaveReturn after the map lookup?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

llvm's map does not have emplace afaict

Copy link
Contributor

Choose a reason for hiding this comment

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

hum, sorry, try_emplace

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");
Expand Down Expand Up @@ -15121,6 +15155,21 @@ ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
return PrimaryBase;
}

bool ASTContext::hasAddressDiscriminatedVTableAuthentication(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that can just be a (static) function declared in this file, taking ASTContext as parameter - it should not be called directly

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Which function?

Copy link
Contributor

Choose a reason for hiding this comment

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

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());
Expand Down
14 changes: 8 additions & 6 deletions clang/lib/Sema/SemaTypeTraits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -322,9 +327,6 @@ bool Sema::IsCXXTriviallyRelocatableType(QualType Type) {
if (BaseElementType.hasNonTrivialObjCLifetime())
return false;

if (BaseElementType.hasAddressDiscriminatedPointerAuth())
return false;

if (BaseElementType->isIncompleteType())
return false;

Expand Down Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/cxx2c-trivially-relocatable.cpp
Original file line number Diff line number Diff line change
@@ -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));
Expand Down
10 changes: 5 additions & 5 deletions clang/test/SemaCXX/ptrauth-triviality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>));
Expand All @@ -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 {
Expand Down Expand Up @@ -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>));

Expand Down Expand Up @@ -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>));
Expand All @@ -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 {
Expand Down
102 changes: 102 additions & 0 deletions clang/test/SemaCXX/trivially-relocatable-ptrauth.cpp
Original file line number Diff line number Diff line change
@@ -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));
Loading