-
Notifications
You must be signed in to change notification settings - Fork 12.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[PAC] Define __builtin_ptrauth_type_discriminator #100204
Conversation
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@apple.com
@llvm/pr-subscribers-backend-x86 @llvm/pr-subscribers-clang Author: Akira Hatanaka (ahatanak) ChangesThe 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@apple.com Full diff: https://github.com/llvm/llvm-project/pull/100204.diff 14 Files Affected:
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'}}
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sema.h
changes look good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly LGTM, but the mangle-fail test should be fixed before merging - now it just does not look correct (see corresponding comment for details #100204 (comment)). Otherwise, this looks nice, and I'm OK with merging as soon as the test is fixed (and if nobody else has other concerns)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
/cherry-pick 666e332 |
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@apple.com (cherry picked from commit 666e332)
/pull-request #100332 |
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@apple.com (cherry picked from commit 666e332)
Summary: 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@apple.com Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60250631
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@apple.com
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@apple.com