Skip to content

Commit 36d7697

Browse files
committed
[clang][PAC] Fix builtins that claim Address discriminated types are copyable
A number of builtins report some variation of "this type is compatibile with some bitwise equivalent operation", but this is not true for address discriminated values. We had address a number of cases, but not all of them. This PR corrects the remaining builtins. Fixes #154394
1 parent 803edce commit 36d7697

File tree

5 files changed

+171
-9
lines changed

5 files changed

+171
-9
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
640640
/// contain data that is address discriminated. This includes
641641
/// implicitly authenticated values like vtable pointers, as well as
642642
/// explicitly qualified fields.
643-
bool containsAddressDiscriminatedPointerAuth(QualType T) {
643+
bool containsAddressDiscriminatedPointerAuth(QualType T) const {
644644
if (!isPointerAuthenticationAvailable())
645645
return false;
646646
return findPointerAuthContent(T) != PointerAuthContent::None;
@@ -654,8 +654,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
654654
bool containsNonRelocatablePointerAuth(QualType T) {
655655
if (!isPointerAuthenticationAvailable())
656656
return false;
657-
return findPointerAuthContent(T) ==
658-
PointerAuthContent::AddressDiscriminatedData;
657+
return findPointerAuthContent(T) !=
658+
PointerAuthContent::None;
659659
}
660660

661661
private:
@@ -673,8 +673,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
673673
bool isPointerAuthenticationAvailable() const {
674674
return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics;
675675
}
676-
PointerAuthContent findPointerAuthContent(QualType T);
677-
llvm::DenseMap<const RecordDecl *, PointerAuthContent>
676+
PointerAuthContent findPointerAuthContent(QualType T) const;
677+
mutable llvm::DenseMap<const RecordDecl *, PointerAuthContent>
678678
RecordContainsAddressDiscriminatedPointerAuth;
679679

680680
ImportDecl *FirstLocalImport = nullptr;
@@ -3720,7 +3720,7 @@ OPT_LIST(V)
37203720
/// Resolve the root record to be used to derive the vtable pointer
37213721
/// authentication policy for the specified record.
37223722
const CXXRecordDecl *
3723-
baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
3723+
baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const;
37243724

37253725
bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
37263726
StringRef MangledName);

clang/lib/AST/ASTContext.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,7 @@ void ASTContext::setRelocationInfoForCXXRecord(
17081708
}
17091709

17101710
static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication(
1711-
ASTContext &Context, const CXXRecordDecl *Class) {
1711+
const ASTContext &Context, const CXXRecordDecl *Class) {
17121712
if (!Class->isPolymorphic())
17131713
return false;
17141714
const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class);
@@ -1723,7 +1723,7 @@ static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication(
17231723
return AddressDiscrimination == AuthAttr::AddressDiscrimination;
17241724
}
17251725

1726-
ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) {
1726+
ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) const {
17271727
assert(isPointerAuthenticationAvailable());
17281728

17291729
T = T.getCanonicalType();
@@ -15175,7 +15175,7 @@ StringRef ASTContext::getCUIDHash() const {
1517515175
}
1517615176

1517715177
const CXXRecordDecl *
15178-
ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
15178+
ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const {
1517915179
assert(ThisClass);
1518015180
assert(ThisClass->isPolymorphic());
1518115181
const CXXRecordDecl *PrimaryBase = ThisClass;

clang/lib/AST/DeclCXX.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
14381438
data().StructuralIfLiteral = false;
14391439
}
14401440

1441+
if (!data().HasTrivialSpecialMembers && T.hasAddressDiscriminatedPointerAuth()) {
1442+
// Address discriminated fields mean that a class is no longer
1443+
// standard layout.
1444+
data().HasTrivialSpecialMembers = true;
1445+
}
1446+
14411447
// C++14 [meta.unary.prop]p4:
14421448
// T is a class type [...] with [...] no non-static data members other
14431449
// than subobjects of zero size

clang/lib/AST/Type.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,6 +2771,11 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const {
27712771
return false;
27722772

27732773
QualType CanonicalType = getTypePtr()->CanonicalType;
2774+
2775+
// Any type that is, or contains, address discriminated data is non-POD
2776+
if (CanonicalType.hasAddressDiscriminatedPointerAuth())// Context.containsAddressDiscriminatedPointerAuth(*this))
2777+
return false;
2778+
27742779
switch (CanonicalType->getTypeClass()) {
27752780
// Everything not explicitly mentioned is not POD.
27762781
default:
@@ -2829,6 +2834,10 @@ bool QualType::isTrivialType(const ASTContext &Context) const {
28292834
if (CanonicalType->isDependentType())
28302835
return false;
28312836

2837+
// Any type that is, or contains, address discriminated data is non-POD
2838+
if (CanonicalType.hasAddressDiscriminatedPointerAuth()) // Context.containsAddressDiscriminatedPointerAuth(CanonicalType))
2839+
return false;
2840+
28322841
// C++0x [basic.types]p9:
28332842
// Scalar types, trivial class types, arrays of such types, and
28342843
// cv-qualified versions of these types are collectively called trivial
@@ -3179,6 +3188,10 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const {
31793188
if (BaseTy->isIncompleteType())
31803189
return false;
31813190

3191+
// Any type that is, or contains, address discriminated data is non-POD
3192+
if (getCanonicalType().hasAddressDiscriminatedPointerAuth()) // Context.containsAddressDiscriminatedPointerAuth(*this))
3193+
return false;
3194+
31823195
// As an extension, Clang treats vector types as Scalar types.
31833196
if (BaseTy->isScalarType() || BaseTy->isVectorType())
31843197
return true;
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// RUN: %clang_cc1 -triple arm64 -std=c++26 -Wno-deprecated-builtins \
2+
// RUN: -fsyntax-only -verify %s
3+
// RUN: %clang_cc1 -triple arm64-apple-darwin -fptrauth-calls -fptrauth-intrinsics \
4+
// RUN: -fptrauth-vtable-pointer-address-discrimination \
5+
// RUN: -std=c++26 -Wno-deprecated-builtins \
6+
// RUN: -fsyntax-only -verify %s
7+
8+
// expected-no-diagnostics
9+
10+
#ifdef __PTRAUTH__
11+
12+
#define NonAddressDiscriminatedVTablePtrAttr \
13+
[[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]]
14+
#define AddressDiscriminatedVTablePtrAttr \
15+
[[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, no_extra_discrimination)]]
16+
#define ADDR_DISC_ENABLED true
17+
#else
18+
#define NonAddressDiscriminatedVTablePtrAttr
19+
#define AddressDiscriminatedVTablePtrAttr
20+
#define ADDR_DISC_ENABLED false
21+
#define __ptrauth(...)
22+
#endif
23+
24+
25+
typedef int* __ptrauth(1,1,1) AddressDiscriminatedPtr;
26+
typedef __UINT64_TYPE__ __ptrauth(1,1,1) AddressDiscriminatedInt64;
27+
struct AddressDiscriminatedFields {
28+
AddressDiscriminatedPtr ptr;
29+
};
30+
struct RelocatableAddressDiscriminatedFields trivially_relocatable_if_eligible {
31+
AddressDiscriminatedPtr ptr;
32+
};
33+
struct AddressDiscriminatedFieldInBaseClass : AddressDiscriminatedFields {
34+
void *newfield;
35+
};
36+
37+
struct NonAddressDiscriminatedVTablePtrAttr NonAddressDiscriminatedVTablePtr {
38+
virtual ~NonAddressDiscriminatedVTablePtr();
39+
void *i;
40+
};
41+
42+
struct NonAddressDiscriminatedVTablePtrAttr NonAddressDiscriminatedVTablePtr2 {
43+
virtual ~NonAddressDiscriminatedVTablePtr2();
44+
void *j;
45+
};
46+
47+
struct NonAddressDiscriminatedVTablePtrAttr RelocatableNonAddressDiscriminatedVTablePtr trivially_relocatable_if_eligible {
48+
virtual ~RelocatableNonAddressDiscriminatedVTablePtr();
49+
void *i;
50+
};
51+
52+
struct NonAddressDiscriminatedVTablePtrAttr RelocatableNonAddressDiscriminatedVTablePtr2 trivially_relocatable_if_eligible {
53+
virtual ~RelocatableNonAddressDiscriminatedVTablePtr2();
54+
void *j;
55+
};
56+
57+
struct AddressDiscriminatedVTablePtrAttr AddressDiscriminatedVTablePtr {
58+
virtual ~AddressDiscriminatedVTablePtr();
59+
void *k;
60+
};
61+
62+
struct AddressDiscriminatedVTablePtrAttr RelocatableAddressDiscriminatedVTablePtr trivially_relocatable_if_eligible {
63+
virtual ~RelocatableAddressDiscriminatedVTablePtr();
64+
void *k;
65+
};
66+
67+
struct NoAddressDiscriminatedBaseClasses : NonAddressDiscriminatedVTablePtr,
68+
NonAddressDiscriminatedVTablePtr2 {
69+
void *l;
70+
};
71+
72+
struct RelocatableNoAddressDiscriminatedBaseClasses trivially_relocatable_if_eligible :
73+
NonAddressDiscriminatedVTablePtr,
74+
NonAddressDiscriminatedVTablePtr2 {
75+
void *l;
76+
};
77+
78+
struct AddressDiscriminatedPrimaryBase : AddressDiscriminatedVTablePtr,
79+
NonAddressDiscriminatedVTablePtr {
80+
void *l;
81+
};
82+
struct AddressDiscriminatedSecondaryBase : NonAddressDiscriminatedVTablePtr,
83+
AddressDiscriminatedVTablePtr {
84+
void *l;
85+
};
86+
87+
struct RelocatableAddressDiscriminatedPrimaryBase : RelocatableAddressDiscriminatedVTablePtr,
88+
RelocatableNonAddressDiscriminatedVTablePtr {
89+
void *l;
90+
};
91+
struct RelocatableAddressDiscriminatedSecondaryBase : RelocatableNonAddressDiscriminatedVTablePtr,
92+
RelocatableAddressDiscriminatedVTablePtr {
93+
void *l;
94+
};
95+
struct EmbdeddedAddressDiscriminatedPolymorphicClass {
96+
AddressDiscriminatedVTablePtr field;
97+
};
98+
struct RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass trivially_relocatable_if_eligible {
99+
AddressDiscriminatedVTablePtr field;
100+
};
101+
102+
#define ASSERT_BUILTIN_EQUALS(Expression, Predicate, Info) \
103+
static_assert((Expression) == (([](bool Polymorphic, bool AddrDisc, bool Relocatable, bool HasNonstandardLayout){ return (Predicate); })Info), #Expression);
104+
//, #Expression " did not match " #Predicate);
105+
106+
107+
#define TEST_BUILTINS(Builtin, Predicate) \
108+
ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedPtr), Predicate, (false, ADDR_DISC_ENABLED, true, false)) \
109+
ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedInt64), Predicate, (false, ADDR_DISC_ENABLED, true, false))\
110+
ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedFields), Predicate, (false, ADDR_DISC_ENABLED, true, false))\
111+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedFields), Predicate, (false, ADDR_DISC_ENABLED, true, false))\
112+
ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedFieldInBaseClass), Predicate, (false, ADDR_DISC_ENABLED, true, true))\
113+
ASSERT_BUILTIN_EQUALS(Builtin(NonAddressDiscriminatedVTablePtr), Predicate, (true, false, false, false))\
114+
ASSERT_BUILTIN_EQUALS(Builtin(NonAddressDiscriminatedVTablePtr2), Predicate, (true, false, false, false))\
115+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNonAddressDiscriminatedVTablePtr), Predicate, (true, false, true, true))\
116+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNonAddressDiscriminatedVTablePtr2), Predicate, (true, false, true, true))\
117+
ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedVTablePtr), Predicate, (true, ADDR_DISC_ENABLED, false, true))\
118+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedVTablePtr), Predicate, (true, ADDR_DISC_ENABLED, true, true))\
119+
ASSERT_BUILTIN_EQUALS(Builtin(NoAddressDiscriminatedBaseClasses), Predicate, (true, false, false, true))\
120+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableNoAddressDiscriminatedBaseClasses), Predicate, (true, false, false, true))\
121+
ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedPrimaryBase), Predicate, (true, ADDR_DISC_ENABLED, false, true))\
122+
ASSERT_BUILTIN_EQUALS(Builtin(AddressDiscriminatedSecondaryBase), Predicate, (true, ADDR_DISC_ENABLED, false, true))\
123+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedPrimaryBase), Predicate, (true, ADDR_DISC_ENABLED, true, true))\
124+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableAddressDiscriminatedSecondaryBase), Predicate, (true, ADDR_DISC_ENABLED, true, true))\
125+
ASSERT_BUILTIN_EQUALS(Builtin(EmbdeddedAddressDiscriminatedPolymorphicClass), Predicate, (true, ADDR_DISC_ENABLED, false, true))\
126+
ASSERT_BUILTIN_EQUALS(Builtin(RelocatableEmbdeddedAddressDiscriminatedPolymorphicClass), Predicate, (true, ADDR_DISC_ENABLED, false, true))
127+
128+
TEST_BUILTINS(__is_pod, !(Polymorphic || AddrDisc || HasNonstandardLayout))
129+
TEST_BUILTINS(__is_standard_layout, !(Polymorphic || HasNonstandardLayout))
130+
TEST_BUILTINS(__has_trivial_move_constructor, !(Polymorphic || AddrDisc))
131+
TEST_BUILTINS(__has_trivial_copy, !(Polymorphic || AddrDisc))
132+
TEST_BUILTINS(__has_trivial_assign, !(Polymorphic || AddrDisc))
133+
TEST_BUILTINS(__has_trivial_move_assign, !(Polymorphic || AddrDisc))
134+
TEST_BUILTINS(__is_trivial, !(Polymorphic || AddrDisc))
135+
TEST_BUILTINS(__is_trivially_copyable, !(Polymorphic || AddrDisc))
136+
TEST_BUILTINS(__is_trivially_copyable, !(Polymorphic || AddrDisc))
137+
TEST_BUILTINS(__is_trivially_relocatable, !((Polymorphic) || AddrDisc))
138+
TEST_BUILTINS(__builtin_is_cpp_trivially_relocatable, !((Polymorphic && !Relocatable) || AddrDisc))
139+
TEST_BUILTINS(__builtin_is_replaceable, !(Polymorphic || AddrDisc))
140+
TEST_BUILTINS(__is_bitwise_cloneable, !AddrDisc);
141+
142+
#define ASSIGNABLE_WRAPPER(Type) __is_trivially_assignable(Type&, Type)
143+
TEST_BUILTINS(ASSIGNABLE_WRAPPER, !(Polymorphic || AddrDisc))

0 commit comments

Comments
 (0)