Skip to content

Commit cf5921c

Browse files
committed
[PAC][clang] Correct handling of ptrauth queries of incomplete types
In normal circumstances we can never get to this point as earlier Sema checks will have already have prevented us from making these queries. However in some cases, for example a sufficiently large number of errors, clang can start allowing incomplete types in records. This means a number of the internal interfaces can end up perform type trait queries that require querying the pointer authentication properties of types that contain incomplete types. While the trait queries attempt to guard against incomplete types, those tests fail in this case as the incomplete types are actually nested in the seemingly complete parent type.
1 parent 6b9a9cf commit cf5921c

File tree

2 files changed

+62
-2
lines changed

2 files changed

+62
-2
lines changed

clang/lib/AST/ASTContext.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,8 +1618,26 @@ void ASTContext::setRelocationInfoForCXXRecord(
16181618
RelocatableClasses.insert({D, Info});
16191619
}
16201620

1621+
// In future we may want to distinguish the presence or absence of address
1622+
// discrimination, from the inability to determine the presence. For now we rely
1623+
// on all source facing interfaces (type trait queries, etc) diagnosing and
1624+
// reporting an error before reaching these paths.
1625+
static bool canDeterminePointerAuthContent(QualType Type) {
1626+
if (Type->isIncompleteType() || Type->isDependentType())
1627+
return false;
1628+
const TagDecl *Decl = Type->getAsTagDecl();
1629+
return !Decl || !Decl->getDefinition()->isInvalidDecl();
1630+
}
1631+
static bool canDeterminePointerAuthContent(const ASTContext &Ctx,
1632+
const TagDecl *Decl) {
1633+
CanQualType DeclType = Ctx.getCanonicalTagType(Decl);
1634+
return canDeterminePointerAuthContent(DeclType);
1635+
}
1636+
16211637
static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication(
16221638
const ASTContext &Context, const CXXRecordDecl *Class) {
1639+
if (!canDeterminePointerAuthContent(Context, Class))
1640+
return false;
16231641
if (!Class->isPolymorphic())
16241642
return false;
16251643
const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class);
@@ -1639,7 +1657,7 @@ ASTContext::findPointerAuthContent(QualType T) const {
16391657
assert(isPointerAuthenticationAvailable());
16401658

16411659
T = T.getCanonicalType();
1642-
if (T->isDependentType())
1660+
if (!canDeterminePointerAuthContent(T))
16431661
return PointerAuthContent::None;
16441662

16451663
if (T.hasAddressDiscriminatedPointerAuth())
@@ -3230,6 +3248,7 @@ QualType ASTContext::removeAddrSpaceQualType(QualType T) const {
32303248

32313249
uint16_t
32323250
ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD) {
3251+
assert(canDeterminePointerAuthContent(*this, RD));
32333252
assert(RD->isPolymorphic() &&
32343253
"Attempted to get vtable pointer discriminator on a monomorphic type");
32353254
std::unique_ptr<MangleContext> MC(createMangleContext());
@@ -3517,7 +3536,9 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
35173536
uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) {
35183537
assert(!T->isDependentType() &&
35193538
"cannot compute type discriminator of a dependent type");
3520-
3539+
assert(canDeterminePointerAuthContent(T) &&
3540+
"cannot compute type discriminator of an incomplete or otherwise "
3541+
"invalid type");
35213542
SmallString<256> Str;
35223543
llvm::raw_svector_ostream Out(Str);
35233544

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %clang_cc1 -fptrauth-intrinsics -fsyntax-only -ferror-limit 1 -verify -std=c++26 %s
2+
// RUN: %clang_cc1 -fptrauth-intrinsics -fsyntax-only -ferror-limit 1 -verify -std=c++03 %s
3+
// RUN: %clang_cc1 -fsyntax-only -ferror-limit 1 -verify -std=c++03 %s
4+
5+
/// Force two errors so we hit the error limit leading to skip of template instantiation
6+
# "" // expected-error {{invalid preprocessing directive}}
7+
# ""
8+
// expected-error@* {{too many errors emitted}}
9+
10+
template <typename>
11+
struct a {};
12+
struct test_polymorphic {
13+
virtual ~test_polymorphic();
14+
a<int> field;
15+
};
16+
static_assert(__is_trivially_relocatable(test_polymorphic));
17+
18+
struct test_struct {
19+
test_struct(int) {}
20+
void test_instantiate() {
21+
test_struct d(0);
22+
}
23+
void test_type_trait_query() {
24+
__is_trivially_relocatable(test_struct);
25+
}
26+
a<int> e;
27+
};
28+
29+
struct test_subclass : test_struct {
30+
test_subclass() : test_struct(0) {
31+
}
32+
33+
void test_subclass_instantiation() {
34+
test_subclass subclass{};
35+
}
36+
void test_subclass_type_trait_query() {
37+
__is_trivially_relocatable(test_subclass);
38+
}
39+
};

0 commit comments

Comments
 (0)