[clang] [PAC] Define __builtin_ptrauth_type_discriminator (PR #100204)
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 23 13:50:03 PDT 2024
https://github.com/ahatanak created https://github.com/llvm/llvm-project/pull/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 rjmccall at apple.com
>From 4cbbf9ee2c5afaa3818c10ab6f2645353da94a8c Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Tue, 23 Jul 2024 11:55:57 -0700
Subject: [PATCH] [PAC] Define __builtin_ptrauth_type_discriminator
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 rjmccall at apple.com
---
.../clang/Basic/DiagnosticSemaKinds.td | 3 +
clang/include/clang/Basic/TokenKinds.def | 2 +
clang/include/clang/Parse/Parser.h | 2 +
clang/include/clang/Sema/Sema.h | 2 +
clang/lib/AST/ExprConstant.cpp | 6 ++
clang/lib/AST/ItaniumMangle.cpp | 8 +++
clang/lib/Headers/ptrauth.h | 19 ++++++
clang/lib/Parse/ParseExpr.cpp | 23 +++++++
clang/lib/Sema/SemaChecking.cpp | 10 ++-
clang/lib/Sema/SemaExpr.cpp | 19 ++++++
clang/test/AST/ast-dump-ptrauth-json.cpp | 5 ++
clang/test/CodeGenCXX/mangle-fail.cpp | 14 ++++
clang/test/Sema/ptrauth-intrinsics-macro.c | 5 ++
.../SemaCXX/ptrauth-type-discriminator.cpp | 64 +++++++++++++++++++
14 files changed, 179 insertions(+), 3 deletions(-)
create mode 100644 clang/test/AST/ast-dump-ptrauth-json.cpp
create mode 100644 clang/test/SemaCXX/ptrauth-type-discriminator.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 00affee1ea67f..045c493e88c31 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -942,6 +942,9 @@ def warn_ptrauth_auth_null_pointer :
InGroup<PtrAuthNullPointers>;
def err_ptrauth_string_not_literal : Error<
"argument must be a string literal%select{| of char type}0">;
+def err_ptrauth_type_disc_undiscriminated : Error<
+ "cannot pass undiscriminated type %0 to "
+ "'__builtin_ptrauth_type_discriminator'">;
def note_ptrauth_virtual_function_pointer_incomplete_arg_ret :
Note<"cannot take an address of a virtual member function if its return or "
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 7f4912b9bcd96..8c54661e65cf4 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -596,6 +596,8 @@ ALIAS("__is_same_as", __is_same, KEYCXX)
KEYWORD(__private_extern__ , KEYALL)
KEYWORD(__module_private__ , KEYALL)
+UNARY_EXPR_OR_TYPE_TRAIT(__builtin_ptrauth_type_discriminator, PtrAuthTypeDiscriminator, KEYALL)
+
// Extension that will be enabled for Microsoft, Borland and PS4, but can be
// disabled via '-fno-declspec'.
KEYWORD(__declspec , 0)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 613bab9120dfc..35bb1a19d40f0 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3890,6 +3890,8 @@ class Parser : public CodeCompletionHandler {
ExprResult ParseArrayTypeTrait();
ExprResult ParseExpressionTrait();
+ ExprResult ParseBuiltinPtrauthTypeDiscriminator();
+
//===--------------------------------------------------------------------===//
// Preprocessor code-completion pass-through
void CodeCompleteDirective(bool InConditional) override;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d638d31e050dc..7bfdaaae45a93 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3456,6 +3456,8 @@ class Sema final : public SemaBase {
TemplateIdAnnotation *TemplateId,
bool IsMemberSpecialization);
+ bool checkPointerAuthEnabled(SourceLocation Loc, SourceRange Range);
+
bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key);
/// Diagnose function specifiers on a declaration of an identifier that
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fcb382474ea62..03a606102a77e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -14054,6 +14054,12 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
E);
}
+ case UETT_PtrAuthTypeDiscriminator: {
+ if (E->getArgumentType()->isDependentType())
+ return false;
+ return Success(
+ Info.Ctx.getPointerAuthTypeDiscriminator(E->getArgumentType()), E);
+ }
case UETT_VecStep: {
QualType Ty = E->getTypeOfArgument();
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 40ef82785f454..d46d621d4c7d4 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5179,6 +5179,14 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
Diags.Report(DiagID);
return;
}
+ case UETT_PtrAuthTypeDiscriminator: {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "cannot yet mangle __builtin_ptrauth_type_discriminator expression");
+ Diags.Report(E->getExprLoc(), DiagID);
+ return;
+ }
case UETT_VecStep: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index e0bc8c4f9acf7..4724155b0dc79 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -202,6 +202,23 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
#define ptrauth_string_discriminator(__string) \
__builtin_ptrauth_string_discriminator(__string)
+/* Compute a constant discriminator from the given type.
+
+ The result can be used as the second argument to
+ ptrauth_blend_discriminator or the third argument to the
+ __ptrauth qualifier. It has type size_t.
+
+ If the type 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 macro with any
+ other type.
+
+ A call to this function is an integer constant expression. */
+#define ptrauth_type_discriminator(__type) \
+ __builtin_ptrauth_type_discriminator(__type)
+
/* Compute a signature for the given pair of pointer-sized values.
The order of the arguments is significant.
@@ -289,6 +306,8 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
((ptrauth_extra_data_t)0); \
})
+#define ptrauth_type_discriminator(__type) ((ptrauth_extra_data_t)0)
+
#define ptrauth_sign_generic_data(__value, __data) \
({ \
(void)__value; \
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index a12c375c8d48c..0a017ae79de75 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -841,6 +841,26 @@ bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II,
return false;
}
+ExprResult Parser::ParseBuiltinPtrauthTypeDiscriminator() {
+ SourceLocation Loc = ConsumeToken();
+
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume())
+ return ExprError();
+
+ TypeResult Ty = ParseTypeName();
+ if (Ty.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return ExprError();
+ }
+
+ SourceLocation EndLoc = Tok.getLocation();
+ T.consumeClose();
+ return Actions.ActOnUnaryExprOrTypeTraitExpr(
+ Loc, UETT_PtrAuthTypeDiscriminator,
+ /*isType=*/true, Ty.get().getAsOpaquePtr(), SourceRange(Loc, EndLoc));
+}
+
/// Parse a cast-expression, or, if \pisUnaryExpression is true, parse
/// a unary-expression.
///
@@ -1806,6 +1826,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
Res = ParseArrayTypeTrait();
break;
+ case tok::kw___builtin_ptrauth_type_discriminator:
+ return ParseBuiltinPtrauthTypeDiscriminator();
+
case tok::kw___is_lvalue_expr:
case tok::kw___is_rvalue_expr:
if (NotPrimaryExpression)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 45b9bbb23dbf7..cf1196ad23c21 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1489,14 +1489,18 @@ enum PointerAuthOpKind {
};
}
-static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
- if (S.getLangOpts().PointerAuthIntrinsics)
+bool Sema::checkPointerAuthEnabled(SourceLocation Loc, SourceRange Range) {
+ if (getLangOpts().PointerAuthIntrinsics)
return false;
- S.Diag(E->getExprLoc(), diag::err_ptrauth_disabled) << E->getSourceRange();
+ Diag(Loc, diag::err_ptrauth_disabled) << Range;
return true;
}
+static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
+ return S.checkPointerAuthEnabled(E->getExprLoc(), E->getSourceRange());
+}
+
static bool checkPointerAuthKey(Sema &S, Expr *&Arg) {
// Convert it to type 'int'.
if (convertArgumentToType(S, Arg, S.Context.IntTy))
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 439db55668cc6..9207bf7a41349 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4117,6 +4117,21 @@ static bool CheckVectorElementsTraitOperandType(Sema &S, QualType T,
return false;
}
+static bool checkPtrAuthTypeDiscriminatorOperandType(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange) {
+ if (S.checkPointerAuthEnabled(Loc, ArgRange))
+ return true;
+
+ if (!T->isFunctionType() && !T->isFunctionPointerType() &&
+ !T->isFunctionReferenceType() && !T->isMemberFunctionPointerType()) {
+ S.Diag(Loc, diag::err_ptrauth_type_disc_undiscriminated) << T << ArgRange;
+ return true;
+ }
+
+ return false;
+}
+
static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
SourceLocation Loc,
SourceRange ArgRange,
@@ -4511,6 +4526,10 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
return CheckVectorElementsTraitOperandType(*this, ExprType, OpLoc,
ExprRange);
+ if (ExprKind == UETT_PtrAuthTypeDiscriminator)
+ return checkPtrAuthTypeDiscriminatorOperandType(*this, ExprType, OpLoc,
+ ExprRange);
+
// Explicitly list some types as extensions.
if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
ExprKind))
diff --git a/clang/test/AST/ast-dump-ptrauth-json.cpp b/clang/test/AST/ast-dump-ptrauth-json.cpp
new file mode 100644
index 0000000000000..125cda0cff53a
--- /dev/null
+++ b/clang/test/AST/ast-dump-ptrauth-json.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -std=c++11 -ast-dump=json %s | FileCheck %s
+
+// CHECK: "name": "__builtin_ptrauth_type_discriminator",
+
+int d = __builtin_ptrauth_type_discriminator(int());
diff --git a/clang/test/CodeGenCXX/mangle-fail.cpp b/clang/test/CodeGenCXX/mangle-fail.cpp
index b588d57749fa3..cac95cabbab83 100644
--- a/clang/test/CodeGenCXX/mangle-fail.cpp
+++ b/clang/test/CodeGenCXX/mangle-fail.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=1
// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=2
+// RUN: %clang_cc1 -emit-llvm-only -x c++ -std=c++11 -triple %itanium_abi_triple -verify %s -DN=3
struct A { int a; };
@@ -13,6 +14,19 @@ template void test<int>(int (&)[sizeof(int)]);
template<class T> void test(int (&)[sizeof((A){}, T())]) {} // expected-error {{cannot yet mangle}}
template void test<int>(int (&)[sizeof(A)]);
+#elif N == 3
+// __builtin_ptrauth_type_discriminator
+template <class T, unsigned disc>
+struct S1 {};
+
+template<class T>
+void func(S1<T, __builtin_ptrauth_type_discriminator(T)> s1) { // expected-error {{cannot yet mangle __builtin_ptrauth_type_discriminator expression}}
+}
+
+void testfunc1() {
+ func(S1<int(), __builtin_ptrauth_type_discriminator(int())>());
+}
+
// FIXME: There are several more cases we can't yet mangle.
#else
diff --git a/clang/test/Sema/ptrauth-intrinsics-macro.c b/clang/test/Sema/ptrauth-intrinsics-macro.c
index f76f677315dd3..adbb71a9d6e50 100644
--- a/clang/test/Sema/ptrauth-intrinsics-macro.c
+++ b/clang/test/Sema/ptrauth-intrinsics-macro.c
@@ -38,6 +38,11 @@ void test_string_discriminator(int *dp) {
(void)t0;
}
+void test_type_discriminator(int *dp) {
+ ptrauth_extra_data_t t0 = ptrauth_type_discriminator(int (*)(int));
+ (void)t0;
+}
+
void test_sign_constant(int *dp) {
dp = ptrauth_sign_constant(&dv, VALID_DATA_KEY, 0);
}
diff --git a/clang/test/SemaCXX/ptrauth-type-discriminator.cpp b/clang/test/SemaCXX/ptrauth-type-discriminator.cpp
new file mode 100644
index 0000000000000..ba2fa0d608d09
--- /dev/null
+++ b/clang/test/SemaCXX/ptrauth-type-discriminator.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s
+
+// RUN: not %clang_cc1 -triple arm64-apple-ios -std=c++17 -Wno-vla -fsyntax-only %s 2>&1 | FileCheck %s
+// CHECK: this target does not support pointer authentication
+
+struct S {
+ virtual int foo();
+};
+
+template <class T>
+constexpr unsigned dependentOperandDisc() {
+ return __builtin_ptrauth_type_discriminator(T);
+}
+
+void test_builtin_ptrauth_type_discriminator(unsigned s) {
+ typedef int (S::*MemFnTy)();
+ MemFnTy memFnPtr;
+ int (S::*memFnPtr2)();
+ constexpr unsigned d0 = __builtin_ptrauth_type_discriminator(MemFnTy);
+ static_assert(d0 == __builtin_ptrauth_string_discriminator("_ZTSM1SFivE"));
+ static_assert(d0 == 60844);
+ static_assert(__builtin_ptrauth_type_discriminator(int (S::*)()) == d0);
+ static_assert(__builtin_ptrauth_type_discriminator(decltype(memFnPtr)) == d0);
+ static_assert(__builtin_ptrauth_type_discriminator(decltype(memFnPtr2)) == d0);
+ static_assert(__builtin_ptrauth_type_discriminator(decltype(&S::foo)) == d0);
+ static_assert(dependentOperandDisc<decltype(&S::foo)>() == d0);
+
+ constexpr unsigned d1 = __builtin_ptrauth_type_discriminator(void (S::*)(int));
+ static_assert(__builtin_ptrauth_string_discriminator("_ZTSM1SFviE") == d1);
+ static_assert(d1 == 39121);
+
+ constexpr unsigned d2 = __builtin_ptrauth_type_discriminator(void (S::*)(float));
+ static_assert(__builtin_ptrauth_string_discriminator("_ZTSM1SFvfE") == d2);
+ static_assert(d2 == 52453);
+
+ constexpr unsigned d3 = __builtin_ptrauth_type_discriminator(int (*())[s]);
+ static_assert(__builtin_ptrauth_string_discriminator("FPE") == d3);
+ static_assert(d3 == 34128);
+
+ int f4(float);
+ constexpr unsigned d4 = __builtin_ptrauth_type_discriminator(decltype(f4));
+ static_assert(__builtin_ptrauth_type_discriminator(int (*)(float)) == d4);
+ static_assert(__builtin_ptrauth_string_discriminator("FifE") == d4);
+ static_assert(d4 == 48468);
+
+ int f5(int);
+ constexpr unsigned d5 = __builtin_ptrauth_type_discriminator(decltype(f5));
+ static_assert(__builtin_ptrauth_type_discriminator(int (*)(int)) == d5);
+ static_assert(__builtin_ptrauth_type_discriminator(short (*)(short)) == d5);
+ static_assert(__builtin_ptrauth_type_discriminator(char (*)(char)) == d5);
+ static_assert(__builtin_ptrauth_type_discriminator(long (*)(long)) == d5);
+ static_assert(__builtin_ptrauth_type_discriminator(unsigned int (*)(unsigned int)) == d5);
+ static_assert(__builtin_ptrauth_type_discriminator(int (&)(int)) == d5);
+ static_assert(__builtin_ptrauth_string_discriminator("FiiE") == d5);
+ static_assert(d5 == 2981);
+
+ int t;
+ int vmarray[s];
+ (void)__builtin_ptrauth_type_discriminator(t); // expected-error {{unknown type name 't'}}
+ (void)__builtin_ptrauth_type_discriminator(&t); // expected-error {{expected a type}}
+ (void)__builtin_ptrauth_type_discriminator(decltype(vmarray)); // expected-error {{cannot pass undiscriminated type 'decltype(vmarray)' (aka 'int[s]')}}
+ (void)__builtin_ptrauth_type_discriminator(int *); // expected-error {{cannot pass undiscriminated type 'int *' to '__builtin_ptrauth_type_discriminator'}}
+}
More information about the cfe-commits
mailing list