Skip to content

Commit 666e332

Browse files
authored
[PAC] Define __builtin_ptrauth_type_discriminator (llvm#100204)
The builtin computes the discriminator for a type, which can be used to sign/authenticate function pointers and member function pointers. If the type passed to the builtin is a C++ member function pointer type, the result is the discriminator used to signed member function pointers of that type. If the type is a function, function pointer, or function reference type, the result is the discriminator used to sign functions of that type. It is ill-formed to use this builtin with any other type. A call to this function is an integer constant expression. Co-Authored-By: John McCall [email protected]
1 parent eff6250 commit 666e332

14 files changed

+183
-3
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,9 @@ def warn_ptrauth_auth_null_pointer :
942942
InGroup<PtrAuthNullPointers>;
943943
def err_ptrauth_string_not_literal : Error<
944944
"argument must be a string literal%select{| of char type}0">;
945+
def err_ptrauth_type_disc_undiscriminated : Error<
946+
"cannot pass undiscriminated type %0 to "
947+
"'__builtin_ptrauth_type_discriminator'">;
945948

946949
def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
947950
Note<"cannot take an address of a virtual member function if its return or "

clang/include/clang/Basic/TokenKinds.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@ ALIAS("__is_same_as", __is_same, KEYCXX)
596596
KEYWORD(__private_extern__ , KEYALL)
597597
KEYWORD(__module_private__ , KEYALL)
598598

599+
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_ptrauth_type_discriminator, PtrAuthTypeDiscriminator, KEYALL)
600+
599601
// Extension that will be enabled for Microsoft, Borland and PS4, but can be
600602
// disabled via '-fno-declspec'.
601603
KEYWORD(__declspec , 0)

clang/include/clang/Parse/Parser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3890,6 +3890,8 @@ class Parser : public CodeCompletionHandler {
38903890
ExprResult ParseArrayTypeTrait();
38913891
ExprResult ParseExpressionTrait();
38923892

3893+
ExprResult ParseBuiltinPtrauthTypeDiscriminator();
3894+
38933895
//===--------------------------------------------------------------------===//
38943896
// Preprocessor code-completion pass-through
38953897
void CodeCompleteDirective(bool InConditional) override;

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3456,6 +3456,8 @@ class Sema final : public SemaBase {
34563456
TemplateIdAnnotation *TemplateId,
34573457
bool IsMemberSpecialization);
34583458

3459+
bool checkPointerAuthEnabled(SourceLocation Loc, SourceRange Range);
3460+
34593461
bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key);
34603462

34613463
/// Diagnose function specifiers on a declaration of an identifier that

clang/lib/AST/ExprConstant.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14058,6 +14058,12 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
1405814058
E);
1405914059
}
1406014060

14061+
case UETT_PtrAuthTypeDiscriminator: {
14062+
if (E->getArgumentType()->isDependentType())
14063+
return false;
14064+
return Success(
14065+
Info.Ctx.getPointerAuthTypeDiscriminator(E->getArgumentType()), E);
14066+
}
1406114067
case UETT_VecStep: {
1406214068
QualType Ty = E->getTypeOfArgument();
1406314069

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5179,6 +5179,14 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
51795179
Diags.Report(DiagID);
51805180
return;
51815181
}
5182+
case UETT_PtrAuthTypeDiscriminator: {
5183+
DiagnosticsEngine &Diags = Context.getDiags();
5184+
unsigned DiagID = Diags.getCustomDiagID(
5185+
DiagnosticsEngine::Error,
5186+
"cannot yet mangle __builtin_ptrauth_type_discriminator expression");
5187+
Diags.Report(E->getExprLoc(), DiagID);
5188+
return;
5189+
}
51825190
case UETT_VecStep: {
51835191
DiagnosticsEngine &Diags = Context.getDiags();
51845192
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,

clang/lib/Headers/ptrauth.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,23 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
202202
#define ptrauth_string_discriminator(__string) \
203203
__builtin_ptrauth_string_discriminator(__string)
204204

205+
/* Compute a constant discriminator from the given type.
206+
207+
The result can be used as the second argument to
208+
ptrauth_blend_discriminator or the third argument to the
209+
__ptrauth qualifier. It has type size_t.
210+
211+
If the type is a C++ member function pointer type, the result is
212+
the discriminator used to signed member function pointers of that
213+
type. If the type is a function, function pointer, or function
214+
reference type, the result is the discriminator used to sign
215+
functions of that type. It is ill-formed to use this macro with any
216+
other type.
217+
218+
A call to this function is an integer constant expression. */
219+
#define ptrauth_type_discriminator(__type) \
220+
__builtin_ptrauth_type_discriminator(__type)
221+
205222
/* Compute a signature for the given pair of pointer-sized values.
206223
The order of the arguments is significant.
207224
@@ -289,6 +306,8 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
289306
((ptrauth_extra_data_t)0); \
290307
})
291308

309+
#define ptrauth_type_discriminator(__type) ((ptrauth_extra_data_t)0)
310+
292311
#define ptrauth_sign_generic_data(__value, __data) \
293312
({ \
294313
(void)__value; \

clang/lib/Parse/ParseExpr.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,26 @@ bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II,
841841
return false;
842842
}
843843

844+
ExprResult Parser::ParseBuiltinPtrauthTypeDiscriminator() {
845+
SourceLocation Loc = ConsumeToken();
846+
847+
BalancedDelimiterTracker T(*this, tok::l_paren);
848+
if (T.expectAndConsume())
849+
return ExprError();
850+
851+
TypeResult Ty = ParseTypeName();
852+
if (Ty.isInvalid()) {
853+
SkipUntil(tok::r_paren, StopAtSemi);
854+
return ExprError();
855+
}
856+
857+
SourceLocation EndLoc = Tok.getLocation();
858+
T.consumeClose();
859+
return Actions.ActOnUnaryExprOrTypeTraitExpr(
860+
Loc, UETT_PtrAuthTypeDiscriminator,
861+
/*isType=*/true, Ty.get().getAsOpaquePtr(), SourceRange(Loc, EndLoc));
862+
}
863+
844864
/// Parse a cast-expression, or, if \pisUnaryExpression is true, parse
845865
/// a unary-expression.
846866
///
@@ -1806,6 +1826,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
18061826
Res = ParseArrayTypeTrait();
18071827
break;
18081828

1829+
case tok::kw___builtin_ptrauth_type_discriminator:
1830+
return ParseBuiltinPtrauthTypeDiscriminator();
1831+
18091832
case tok::kw___is_lvalue_expr:
18101833
case tok::kw___is_rvalue_expr:
18111834
if (NotPrimaryExpression)

clang/lib/Sema/SemaChecking.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,14 +1489,18 @@ enum PointerAuthOpKind {
14891489
};
14901490
}
14911491

1492-
static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
1493-
if (S.getLangOpts().PointerAuthIntrinsics)
1492+
bool Sema::checkPointerAuthEnabled(SourceLocation Loc, SourceRange Range) {
1493+
if (getLangOpts().PointerAuthIntrinsics)
14941494
return false;
14951495

1496-
S.Diag(E->getExprLoc(), diag::err_ptrauth_disabled) << E->getSourceRange();
1496+
Diag(Loc, diag::err_ptrauth_disabled) << Range;
14971497
return true;
14981498
}
14991499

1500+
static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
1501+
return S.checkPointerAuthEnabled(E->getExprLoc(), E->getSourceRange());
1502+
}
1503+
15001504
static bool checkPointerAuthKey(Sema &S, Expr *&Arg) {
15011505
// Convert it to type 'int'.
15021506
if (convertArgumentToType(S, Arg, S.Context.IntTy))

clang/lib/Sema/SemaExpr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4117,6 +4117,21 @@ static bool CheckVectorElementsTraitOperandType(Sema &S, QualType T,
41174117
return false;
41184118
}
41194119

4120+
static bool checkPtrAuthTypeDiscriminatorOperandType(Sema &S, QualType T,
4121+
SourceLocation Loc,
4122+
SourceRange ArgRange) {
4123+
if (S.checkPointerAuthEnabled(Loc, ArgRange))
4124+
return true;
4125+
4126+
if (!T->isFunctionType() && !T->isFunctionPointerType() &&
4127+
!T->isFunctionReferenceType() && !T->isMemberFunctionPointerType()) {
4128+
S.Diag(Loc, diag::err_ptrauth_type_disc_undiscriminated) << T << ArgRange;
4129+
return true;
4130+
}
4131+
4132+
return false;
4133+
}
4134+
41204135
static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
41214136
SourceLocation Loc,
41224137
SourceRange ArgRange,
@@ -4511,6 +4526,10 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
45114526
return CheckVectorElementsTraitOperandType(*this, ExprType, OpLoc,
45124527
ExprRange);
45134528

4529+
if (ExprKind == UETT_PtrAuthTypeDiscriminator)
4530+
return checkPtrAuthTypeDiscriminatorOperandType(*this, ExprType, OpLoc,
4531+
ExprRange);
4532+
45144533
// Explicitly list some types as extensions.
45154534
if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
45164535
ExprKind))
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -std=c++11 -ast-dump=json %s | FileCheck %s
2+
3+
// CHECK: "name": "__builtin_ptrauth_type_discriminator",
4+
5+
int d = __builtin_ptrauth_type_discriminator(int());

clang/test/CodeGenCXX/mangle-fail.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=1
22
// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=2
3+
// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple aarch64-linux-gnu -fptrauth-intrinsics -verify %s -DN=3
34

45
struct A { int a; };
56

@@ -13,6 +14,19 @@ template void test<int>(int (&)[sizeof(int)]);
1314
template<class T> void test(int (&)[sizeof((A){}, T())]) {} // expected-error {{cannot yet mangle}}
1415
template void test<int>(int (&)[sizeof(A)]);
1516

17+
#elif N == 3
18+
// __builtin_ptrauth_type_discriminator
19+
template <class T, unsigned disc>
20+
struct S1 {};
21+
22+
template<class T>
23+
void func(S1<T, __builtin_ptrauth_type_discriminator(T)> s1) { // expected-error {{cannot yet mangle __builtin_ptrauth_type_discriminator expression}}
24+
}
25+
26+
void testfunc1() {
27+
func(S1<int(), __builtin_ptrauth_type_discriminator(int())>());
28+
}
29+
1630
// FIXME: There are several more cases we can't yet mangle.
1731

1832
#else

clang/test/Sema/ptrauth-intrinsics-macro.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ void test_string_discriminator(int *dp) {
3838
(void)t0;
3939
}
4040

41+
void test_type_discriminator(int *dp) {
42+
ptrauth_extra_data_t t0 = ptrauth_type_discriminator(int (*)(int));
43+
(void)t0;
44+
}
45+
4146
void test_sign_constant(int *dp) {
4247
dp = ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
4348
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s
2+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s
3+
4+
// RUN: not %clang_cc1 -triple arm64-apple-ios -std=c++17 -Wno-vla -fsyntax-only %s 2>&1 | FileCheck %s
5+
// CHECK: this target does not support pointer authentication
6+
7+
struct S {
8+
virtual int foo();
9+
};
10+
11+
template <class T>
12+
constexpr unsigned dependentOperandDisc() {
13+
return __builtin_ptrauth_type_discriminator(T);
14+
}
15+
16+
void test_builtin_ptrauth_type_discriminator(unsigned s) {
17+
typedef int (S::*MemFnTy)();
18+
MemFnTy memFnPtr;
19+
int (S::*memFnPtr2)();
20+
constexpr unsigned d0 = __builtin_ptrauth_type_discriminator(MemFnTy);
21+
static_assert(d0 == __builtin_ptrauth_string_discriminator("_ZTSM1SFivE"));
22+
static_assert(d0 == 60844);
23+
static_assert(__builtin_ptrauth_type_discriminator(int (S::*)()) == d0);
24+
static_assert(__builtin_ptrauth_type_discriminator(decltype(memFnPtr)) == d0);
25+
static_assert(__builtin_ptrauth_type_discriminator(decltype(memFnPtr2)) == d0);
26+
static_assert(__builtin_ptrauth_type_discriminator(decltype(&S::foo)) == d0);
27+
static_assert(dependentOperandDisc<decltype(&S::foo)>() == d0);
28+
29+
constexpr unsigned d1 = __builtin_ptrauth_type_discriminator(void (S::*)(int));
30+
static_assert(__builtin_ptrauth_string_discriminator("_ZTSM1SFviE") == d1);
31+
static_assert(d1 == 39121);
32+
33+
constexpr unsigned d2 = __builtin_ptrauth_type_discriminator(void (S::*)(float));
34+
static_assert(__builtin_ptrauth_string_discriminator("_ZTSM1SFvfE") == d2);
35+
static_assert(d2 == 52453);
36+
37+
constexpr unsigned d3 = __builtin_ptrauth_type_discriminator(int (*())[s]);
38+
static_assert(__builtin_ptrauth_string_discriminator("FPE") == d3);
39+
static_assert(d3 == 34128);
40+
41+
int f4(float);
42+
constexpr unsigned d4 = __builtin_ptrauth_type_discriminator(decltype(f4));
43+
static_assert(__builtin_ptrauth_type_discriminator(int (*)(float)) == d4);
44+
static_assert(__builtin_ptrauth_string_discriminator("FifE") == d4);
45+
static_assert(d4 == 48468);
46+
47+
int f5(int);
48+
constexpr unsigned d5 = __builtin_ptrauth_type_discriminator(decltype(f5));
49+
static_assert(__builtin_ptrauth_type_discriminator(int (*)(int)) == d5);
50+
static_assert(__builtin_ptrauth_type_discriminator(short (*)(short)) == d5);
51+
static_assert(__builtin_ptrauth_type_discriminator(char (*)(char)) == d5);
52+
static_assert(__builtin_ptrauth_type_discriminator(long (*)(long)) == d5);
53+
static_assert(__builtin_ptrauth_type_discriminator(unsigned int (*)(unsigned int)) == d5);
54+
static_assert(__builtin_ptrauth_type_discriminator(int (&)(int)) == d5);
55+
static_assert(__builtin_ptrauth_string_discriminator("FiiE") == d5);
56+
static_assert(d5 == 2981);
57+
58+
int t;
59+
int vmarray[s];
60+
(void)__builtin_ptrauth_type_discriminator(t); // expected-error {{unknown type name 't'}}
61+
(void)__builtin_ptrauth_type_discriminator(&t); // expected-error {{expected a type}}
62+
(void)__builtin_ptrauth_type_discriminator(decltype(vmarray)); // expected-error {{cannot pass undiscriminated type 'decltype(vmarray)' (aka 'int[s]')}}
63+
(void)__builtin_ptrauth_type_discriminator(int *); // expected-error {{cannot pass undiscriminated type 'int *' to '__builtin_ptrauth_type_discriminator'}}
64+
(void)__builtin_ptrauth_type_discriminator(); // expected-error {{expected a type}}
65+
(void)__builtin_ptrauth_type_discriminator(int (*)(int), int (*)(int));
66+
// expected-error@-1 {{expected ')'}}
67+
// expected-note@-2 {{to match this '('}}
68+
}

0 commit comments

Comments
 (0)