Skip to content

Commit 50b9193

Browse files
[clang] Define ptrauth_string_discriminator builtin. (llvm#93903)
This exposes the ABI-stable hash function that allows computing a 16-bit discriminator from a constant string. This allows manually matching the implicit string discriminators computed in the ABI (e.g., from mangled names for vtable pointer/entry signing), as well as enabling the use of interesting discriminators when manually annotating specific pointers with the __ptrauth qualifier. The argument must be a string literal of char character type. The result has type ptrauth_extra_data_t. The result value is never zero and always within range for both the __ptrauth qualifier and ptrauth_blend_discriminator. This can be used in constant expressions. Co-authored-by: John McCall <[email protected]>
1 parent 99f5fcb commit 50b9193

File tree

9 files changed

+109
-6
lines changed

9 files changed

+109
-6
lines changed

clang/docs/PointerAuthentication.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,23 @@ be done in a single instruction with an immediate integer.
328328
``pointer`` must have pointer type, and ``integer`` must have integer type. The
329329
result has type ``ptrauth_extra_data_t``.
330330

331+
``ptrauth_string_discriminator``
332+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
333+
334+
.. code-block:: c
335+
336+
ptrauth_string_discriminator(string)
337+
338+
Compute a constant discriminator from the given string.
339+
340+
``string`` must be a string literal of ``char`` character type. The result has
341+
type ``ptrauth_extra_data_t``.
342+
343+
The result value is never zero and always within range for both the
344+
``__ptrauth`` qualifier and ``ptrauth_blend_discriminator``.
345+
346+
This can be used in constant expressions.
347+
331348
``ptrauth_strip``
332349
^^^^^^^^^^^^^^^^^
333350

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4411,6 +4411,12 @@ def PtrauthAuth : Builtin {
44114411
let Prototype = "void*(void*,int,void*)";
44124412
}
44134413

4414+
def PtrauthStringDiscriminator : Builtin {
4415+
let Spellings = ["__builtin_ptrauth_string_discriminator"];
4416+
let Attributes = [NoThrow, Const, Constexpr];
4417+
let Prototype = "size_t(char const*)";
4418+
}
4419+
44144420
// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
44154421
// We need the generic prototype, since the packet type could be anything.
44164422
def ReadPipe : OCLPipeLangBuiltin {

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,8 @@ def warn_ptrauth_sign_null_pointer :
930930
def warn_ptrauth_auth_null_pointer :
931931
Warning<"authenticating a null pointer will almost certainly trap">,
932932
InGroup<PtrAuthNullPointers>;
933+
def err_ptrauth_string_not_literal : Error<
934+
"argument must be a string literal%select{| of char type}0">;
933935

934936
/// main()
935937
// static main() is not an error in C, just in C++.

clang/lib/AST/ExprConstant.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "llvm/ADT/StringExtras.h"
5959
#include "llvm/Support/Debug.h"
6060
#include "llvm/Support/SaveAndRestore.h"
61+
#include "llvm/Support/SipHash.h"
6162
#include "llvm/Support/TimeProfiler.h"
6263
#include "llvm/Support/raw_ostream.h"
6364
#include <cstring>
@@ -12633,6 +12634,13 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1263312634
case Builtin::BI__builtin_expect_with_probability:
1263412635
return Visit(E->getArg(0));
1263512636

12637+
case Builtin::BI__builtin_ptrauth_string_discriminator: {
12638+
const auto *Literal =
12639+
cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
12640+
uint64_t Result = getPointerAuthStableSipHash(Literal->getString());
12641+
return Success(Result, E);
12642+
}
12643+
1263612644
case Builtin::BI__builtin_ffs:
1263712645
case Builtin::BI__builtin_ffsl:
1263812646
case Builtin::BI__builtin_ffsll: {

clang/lib/Headers/ptrauth.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,19 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
125125
#define ptrauth_auth_data(__value, __old_key, __old_data) \
126126
__builtin_ptrauth_auth(__value, __old_key, __old_data)
127127

128+
/* Compute a constant discriminator from the given string.
129+
130+
The argument must be a string literal of char character type. The result
131+
has type ptrauth_extra_data_t.
132+
133+
The result value is never zero and always within range for both the
134+
__ptrauth qualifier and ptrauth_blend_discriminator.
135+
136+
This can be used in constant expressions.
137+
*/
138+
#define ptrauth_string_discriminator(__string) \
139+
__builtin_ptrauth_string_discriminator(__string)
140+
128141
/* Compute a signature for the given pair of pointer-sized values.
129142
The order of the arguments is significant.
130143
@@ -186,6 +199,12 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
186199
__value; \
187200
})
188201

202+
#define ptrauth_string_discriminator(__string) \
203+
({ \
204+
(void)__string; \
205+
((ptrauth_extra_data_t)0); \
206+
})
207+
189208
#define ptrauth_sign_generic_data(__value, __data) \
190209
({ \
191210
(void)__value; \

clang/lib/Sema/SemaChecking.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,24 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
21662166
return Call;
21672167
}
21682168

2169+
static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
2170+
if (checkPointerAuthEnabled(S, Call))
2171+
return ExprError();
2172+
2173+
// We've already performed normal call type-checking.
2174+
const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
2175+
2176+
// Operand must be an ordinary or UTF-8 string literal.
2177+
const auto *Literal = dyn_cast<StringLiteral>(Arg);
2178+
if (!Literal || Literal->getCharByteWidth() != 1) {
2179+
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
2180+
<< (Literal ? 1 : 0) << Arg->getSourceRange();
2181+
return ExprError();
2182+
}
2183+
2184+
return Call;
2185+
}
2186+
21692187
static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
21702188
if (S.checkArgCount(TheCall, 1))
21712189
return ExprError();
@@ -2933,6 +2951,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
29332951
return PointerAuthSignGenericData(*this, TheCall);
29342952
case Builtin::BI__builtin_ptrauth_auth_and_resign:
29352953
return PointerAuthAuthAndResign(*this, TheCall);
2954+
case Builtin::BI__builtin_ptrauth_string_discriminator:
2955+
return PointerAuthStringDiscriminator(*this, TheCall);
29362956
// OpenCL v2.0, s6.13.16 - Pipe functions
29372957
case Builtin::BIread_pipe:
29382958
case Builtin::BIwrite_pipe:

clang/test/CodeGen/ptrauth-intrinsics.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
2+
// RUN: %clang_cc1 -triple aarch64-elf -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
23

34
void (*fnptr)(void);
45
long int_discriminator;
56
void *ptr_discriminator;
67
long signature;
78

8-
// CHECK-LABEL: define void @test_auth()
9+
// CHECK-LABEL: define {{.*}}void @test_auth()
910
void test_auth() {
1011
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
1112
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -17,7 +18,7 @@ void test_auth() {
1718
fnptr = __builtin_ptrauth_auth(fnptr, 0, ptr_discriminator);
1819
}
1920

20-
// CHECK-LABEL: define void @test_strip()
21+
// CHECK-LABEL: define {{.*}}void @test_strip()
2122
void test_strip() {
2223
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
2324
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
@@ -27,7 +28,7 @@ void test_strip() {
2728
fnptr = __builtin_ptrauth_strip(fnptr, 0);
2829
}
2930

30-
// CHECK-LABEL: define void @test_sign_unauthenticated()
31+
// CHECK-LABEL: define {{.*}}void @test_sign_unauthenticated()
3132
void test_sign_unauthenticated() {
3233
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
3334
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -39,7 +40,7 @@ void test_sign_unauthenticated() {
3940
fnptr = __builtin_ptrauth_sign_unauthenticated(fnptr, 0, ptr_discriminator);
4041
}
4142

42-
// CHECK-LABEL: define void @test_auth_and_resign()
43+
// CHECK-LABEL: define {{.*}}void @test_auth_and_resign()
4344
void test_auth_and_resign() {
4445
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
4546
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -51,7 +52,7 @@ void test_auth_and_resign() {
5152
fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
5253
}
5354

54-
// CHECK-LABEL: define void @test_blend_discriminator()
55+
// CHECK-LABEL: define {{.*}}void @test_blend_discriminator()
5556
void test_blend_discriminator() {
5657
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
5758
// CHECK-NEXT: [[DISC:%.*]] = load i64, ptr @int_discriminator,
@@ -61,7 +62,7 @@ void test_blend_discriminator() {
6162
int_discriminator = __builtin_ptrauth_blend_discriminator(fnptr, int_discriminator);
6263
}
6364

64-
// CHECK-LABEL: define void @test_sign_generic_data()
65+
// CHECK-LABEL: define {{.*}}void @test_sign_generic_data()
6566
void test_sign_generic_data() {
6667
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
6768
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -71,3 +72,16 @@ void test_sign_generic_data() {
7172
// CHECK-NEXT: store i64 [[RESULT]], ptr @signature,
7273
signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
7374
}
75+
76+
// CHECK-LABEL: define {{.*}}void @test_string_discriminator()
77+
void test_string_discriminator() {
78+
// CHECK: [[X:%.*]] = alloca i32
79+
80+
// Check a couple of random discriminators used by Swift.
81+
82+
// CHECK: store i32 58298, ptr [[X]],
83+
int x = __builtin_ptrauth_string_discriminator("InitializeWithCopy");
84+
85+
// CHECK: store i32 9112, ptr [[X]],
86+
x = __builtin_ptrauth_string_discriminator("DestroyArray");
87+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,8 @@ void test(int *dp, int value) {
3232
int t2 = ptrauth_sign_generic_data(dp, 0);
3333
(void)t2;
3434
}
35+
36+
void test_string_discriminator(int *dp) {
37+
ptrauth_extra_data_t t0 = ptrauth_string_discriminator("string");
38+
(void)t0;
39+
}

clang/test/Sema/ptrauth.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
4747
float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-error {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
4848
}
4949

50+
void test_string_discriminator(const char *str) {
51+
__builtin_ptrauth_string_discriminator(); // expected-error {{too few arguments}}
52+
__builtin_ptrauth_string_discriminator(str, str); // expected-error {{too many arguments}}
53+
(void) __builtin_ptrauth_string_discriminator("test string"); // no warning
54+
55+
__builtin_ptrauth_string_discriminator(str); // expected-error {{argument must be a string literal}}
56+
__builtin_ptrauth_string_discriminator(L"wide test"); // expected-error {{argument must be a string literal}} expected-warning {{incompatible pointer types passing 'int[10]' to parameter of type 'const char *'}}
57+
58+
void *mismatch = __builtin_ptrauth_string_discriminator("test string"); // expected-error {{incompatible integer to pointer conversion initializing 'void *' with an expression of type 'unsigned long'}}
59+
}
60+
61+
5062
void test_sign_unauthenticated(int *dp, int (*fp)(int)) {
5163
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
5264
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}

0 commit comments

Comments
 (0)