Author: Akira Hatanaka Date: 2024-07-24T02:04:37-07:00 New Revision: 666e3326fedfb6a033494c36c36aa95c4124d642
URL: https://github.com/llvm/llvm-project/commit/666e3326fedfb6a033494c36c36aa95c4124d642 DIFF: https://github.com/llvm/llvm-project/commit/666e3326fedfb6a033494c36c36aa95c4124d642.diff LOG: [PAC] Define __builtin_ptrauth_type_discriminator (#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 rjmcc...@apple.com Added: clang/test/AST/ast-dump-ptrauth-json.cpp clang/test/SemaCXX/ptrauth-type-discriminator.cpp Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/TokenKinds.def clang/include/clang/Parse/Parser.h clang/include/clang/Sema/Sema.h clang/lib/AST/ExprConstant.cpp clang/lib/AST/ItaniumMangle.cpp clang/lib/Headers/ptrauth.h clang/lib/Parse/ParseExpr.cpp clang/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaExpr.cpp clang/test/CodeGenCXX/mangle-fail.cpp clang/test/Sema/ptrauth-intrinsics-macro.c Removed: ################################################################################ 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 ec19bce283fd5..c5c86dee04c5b 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -14058,6 +14058,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..f3b50cfb54dbd 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 aarch64-linux-gnu -fptrauth-intrinsics -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..685ca1f03fddd --- /dev/null +++ b/clang/test/SemaCXX/ptrauth-type-discriminator.cpp @@ -0,0 +1,68 @@ +// 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'}} + (void)__builtin_ptrauth_type_discriminator(); // expected-error {{expected a type}} + (void)__builtin_ptrauth_type_discriminator(int (*)(int), int (*)(int)); + // expected-error@-1 {{expected ')'}} + // expected-note@-2 {{to match this '('}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits