Skip to content

[PAC] Define __builtin_ptrauth_type_discriminator #100204

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

Merged
merged 2 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3890,6 +3890,8 @@ class Parser : public CodeCompletionHandler {
ExprResult ParseArrayTypeTrait();
ExprResult ParseExpressionTrait();

ExprResult ParseBuiltinPtrauthTypeDiscriminator();

//===--------------------------------------------------------------------===//
// Preprocessor code-completion pass-through
void CodeCompleteDirective(bool InConditional) override;
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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; \
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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))
Expand Down
5 changes: 5 additions & 0 deletions clang/test/AST/ast-dump-ptrauth-json.cpp
Original file line number Diff line number Diff line change
@@ -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());
14 changes: 14 additions & 0 deletions clang/test/CodeGenCXX/mangle-fail.cpp
Original file line number Diff line number Diff line change
@@ -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; };

Expand All @@ -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
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Sema/ptrauth-intrinsics-macro.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
68 changes: 68 additions & 0 deletions clang/test/SemaCXX/ptrauth-type-discriminator.cpp
Original file line number Diff line number Diff line change
@@ -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 '('}}
}
Loading