[llvm-branch-commits] [clang] [clang] Define ptrauth_string_discriminator builtin. (PR #93903)
Ahmed Bougacha via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jun 3 13:39:22 PDT 2024
https://github.com/ahmedbougacha updated https://github.com/llvm/llvm-project/pull/93903
>From 61be7a922397d66773a8f4a6e476ea321f52f00c Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Thu, 30 May 2024 17:22:29 -0700
Subject: [PATCH 1/4] [clang] Define ptrauth_string_discriminator builtin.
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.
Co-Authored-By: John McCall <rjmccall at apple.com>
---
clang/include/clang/Basic/Builtins.td | 6 ++++++
.../clang/Basic/DiagnosticSemaKinds.td | 2 ++
clang/lib/AST/ExprConstant.cpp | 7 +++++++
clang/lib/Headers/ptrauth.h | 17 ++++++++++++++++
clang/lib/Sema/SemaChecking.cpp | 20 +++++++++++++++++++
clang/test/CodeGen/ptrauth-intrinsics.c | 13 ++++++++++++
clang/test/Sema/ptrauth-intrinsics-macro.c | 5 +++++
7 files changed, 70 insertions(+)
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..836697632a3bc 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4411,6 +4411,12 @@ def PtrauthAuth : Builtin {
let Prototype = "void*(void*,int,void*)";
}
+def PtrauthStringDiscriminator : Builtin {
+ let Spellings = ["__builtin_ptrauth_string_discriminator"];
+ let Attributes = [NoThrow, Const, Constexpr];
+ let Prototype = "size_t(char const*)";
+}
+
// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
// We need the generic prototype, since the packet type could be anything.
def ReadPipe : OCLPipeLangBuiltin {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f15cba63624ea..64add46248c69 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -928,6 +928,8 @@ def warn_ptrauth_sign_null_pointer :
def warn_ptrauth_auth_null_pointer :
Warning<"authenticating a null pointer will almost certainly trap">,
InGroup<PtrAuthNullPointers>;
+def err_ptrauth_string_not_literal : Error<
+ "argument must be a string literal%select{| of char type}0">;
/// main()
// static main() is not an error in C, just in C++.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..eafecfb5fe5b1 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -58,6 +58,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/SipHash.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
@@ -12583,6 +12584,12 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_expect_with_probability:
return Visit(E->getArg(0));
+ case Builtin::BI__builtin_ptrauth_string_discriminator: {
+ auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
+ auto result = getPointerAuthStableSipHash16(literal->getString());
+ return Success(result, E);
+ }
+
case Builtin::BI__builtin_ffs:
case Builtin::BI__builtin_ffsl:
case Builtin::BI__builtin_ffsll: {
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 036665d75a91b..3e58af1802084 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -135,6 +135,17 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
#define ptrauth_auth_data(__value, __old_key, __old_data) \
__builtin_ptrauth_auth(__value, __old_key, __old_data)
+/* Compute a constant discriminator from the given string.
+
+ 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.
+
+ The argument must be a string literal.
+ A call to this function is an integer constant expression. */
+#define ptrauth_string_discriminator(__string) \
+ __builtin_ptrauth_string_discriminator(__string)
+
/* Compute a signature for the given pair of pointer-sized values.
The order of the arguments is significant.
@@ -196,6 +207,12 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
__value; \
})
+#define ptrauth_string_discriminator(__string) \
+ ({ \
+ (void)__string; \
+ ((ptrauth_extra_data_t)0); \
+ })
+
#define ptrauth_sign_generic_data(__value, __data) \
({ \
(void)__value; \
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c3251f3cc9d81..f6012ef4b3601 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2156,6 +2156,24 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
return Call;
}
+static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *call) {
+ if (checkPointerAuthEnabled(S, call)) return ExprError();
+
+ // We've already performed normal call type-checking.
+ Expr *arg = call->getArgs()[0]->IgnoreParenImpCasts();
+
+ // Operand must be an ordinary or UTF-8 string literal.
+ auto literal = dyn_cast<StringLiteral>(arg);
+ if (!literal || literal->getCharByteWidth() != 1) {
+ S.Diag(arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
+ << (literal ? 1 : 0)
+ << arg->getSourceRange();
+ return ExprError();
+ }
+
+ return call;
+}
+
static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
if (S.checkArgCount(TheCall, 1))
return ExprError();
@@ -2922,6 +2940,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return PointerAuthSignGenericData(*this, TheCall);
case Builtin::BI__builtin_ptrauth_auth_and_resign:
return PointerAuthAuthAndResign(*this, TheCall);
+ case Builtin::BI__builtin_ptrauth_string_discriminator:
+ return PointerAuthStringDiscriminator(*this, TheCall);
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:
diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c
index 17f28dddb3801..d602325da8b17 100644
--- a/clang/test/CodeGen/ptrauth-intrinsics.c
+++ b/clang/test/CodeGen/ptrauth-intrinsics.c
@@ -71,3 +71,16 @@ void test_sign_generic_data() {
// CHECK-NEXT: store i64 [[RESULT]], ptr @signature,
signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
}
+
+// CHECK-LABEL: define void @test_string_discriminator()
+void test_string_discriminator() {
+ // CHECK: [[X:%.*]] = alloca i32
+
+ // Check a couple of random discriminators used by Swift.
+
+ // CHECK: store i32 58298, ptr [[X]],
+ int x = __builtin_ptrauth_string_discriminator("InitializeWithCopy");
+
+ // CHECK: store i32 9112, ptr [[X]],
+ x = __builtin_ptrauth_string_discriminator("DestroyArray");
+}
diff --git a/clang/test/Sema/ptrauth-intrinsics-macro.c b/clang/test/Sema/ptrauth-intrinsics-macro.c
index 07d6374045145..540f2846b7ce1 100644
--- a/clang/test/Sema/ptrauth-intrinsics-macro.c
+++ b/clang/test/Sema/ptrauth-intrinsics-macro.c
@@ -32,3 +32,8 @@ void test(int *dp, int value) {
int t2 = ptrauth_sign_generic_data(dp, 0);
(void)t2;
}
+
+void test_string_discriminator(int *dp) {
+ ptrauth_extra_data_t t0 = ptrauth_string_discriminator("string");
+ (void)t0;
+}
>From 5e0ea2eac4673b842b1aa84e5d32cc18ed051fb5 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 11:00:39 -0700
Subject: [PATCH 2/4] Document ptrauth_string_discriminator in
clang/docs/PointerAuthentication.
---
clang/docs/PointerAuthentication.rst | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/clang/docs/PointerAuthentication.rst b/clang/docs/PointerAuthentication.rst
index 19b3384293aed..bd8bf92984225 100644
--- a/clang/docs/PointerAuthentication.rst
+++ b/clang/docs/PointerAuthentication.rst
@@ -328,6 +328,21 @@ be done in a single instruction with an immediate integer.
``pointer`` must have pointer type, and ``integer`` must have integer type. The
result has type ``ptrauth_extra_data_t``.
+``ptrauth_string_discriminator``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: c
+
+ ptrauth_string_discriminator(string)
+
+Produce a discriminator value for the given string. ``string`` must be
+a string literal of ``char`` character type. The result has type
+``ptrauth_extra_data_t``.
+
+The result is always a constant expression. The result value is never zero and
+always within range for both the ``__ptrauth`` qualifier and
+``ptrauth_blend_discriminator``.
+
``ptrauth_strip``
^^^^^^^^^^^^^^^^^
>From 717e4eb0fdbad297a7496568486f7179adf39996 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 13:32:21 -0700
Subject: [PATCH 3/4] Address review feedback.
- add missing sema test
- also test ELF codegen for intrinsics
- various capitalization and type nits
---
clang/lib/AST/ExprConstant.cpp | 7 ++++---
clang/lib/Sema/SemaChecking.cpp | 18 +++++++++---------
clang/test/CodeGen/ptrauth-intrinsics.c | 15 ++++++++-------
clang/test/Sema/ptrauth.c | 11 +++++++++++
4 files changed, 32 insertions(+), 19 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index eafecfb5fe5b1..4ffe84ccd4516 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -12585,9 +12585,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Visit(E->getArg(0));
case Builtin::BI__builtin_ptrauth_string_discriminator: {
- auto literal = cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
- auto result = getPointerAuthStableSipHash16(literal->getString());
- return Success(result, E);
+ const auto *Literal =
+ cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts());
+ uint64_t Result = getPointerAuthStableSipHash16(Literal->getString());
+ return Success(Result, E);
}
case Builtin::BI__builtin_ffs:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f6012ef4b3601..b69542b9dc74d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2156,22 +2156,22 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
return Call;
}
-static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *call) {
- if (checkPointerAuthEnabled(S, call)) return ExprError();
+static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
+ if (checkPointerAuthEnabled(S, Call)) return ExprError();
// We've already performed normal call type-checking.
- Expr *arg = call->getArgs()[0]->IgnoreParenImpCasts();
+ const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
// Operand must be an ordinary or UTF-8 string literal.
- auto literal = dyn_cast<StringLiteral>(arg);
- if (!literal || literal->getCharByteWidth() != 1) {
- S.Diag(arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
- << (literal ? 1 : 0)
- << arg->getSourceRange();
+ const auto *Literal = dyn_cast<StringLiteral>(Arg);
+ if (!Literal || Literal->getCharByteWidth() != 1) {
+ S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
+ << (Literal ? 1 : 0)
+ << Arg->getSourceRange();
return ExprError();
}
- return call;
+ return Call;
}
static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c
index d602325da8b17..db37d78553769 100644
--- a/clang/test/CodeGen/ptrauth-intrinsics.c
+++ b/clang/test/CodeGen/ptrauth-intrinsics.c
@@ -1,11 +1,12 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-elf -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s
void (*fnptr)(void);
long int_discriminator;
void *ptr_discriminator;
long signature;
-// CHECK-LABEL: define void @test_auth()
+// CHECK-LABEL: define {{.*}}void @test_auth()
void test_auth() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -17,7 +18,7 @@ void test_auth() {
fnptr = __builtin_ptrauth_auth(fnptr, 0, ptr_discriminator);
}
-// CHECK-LABEL: define void @test_strip()
+// CHECK-LABEL: define {{.*}}void @test_strip()
void test_strip() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
@@ -27,7 +28,7 @@ void test_strip() {
fnptr = __builtin_ptrauth_strip(fnptr, 0);
}
-// CHECK-LABEL: define void @test_sign_unauthenticated()
+// CHECK-LABEL: define {{.*}}void @test_sign_unauthenticated()
void test_sign_unauthenticated() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -39,7 +40,7 @@ void test_sign_unauthenticated() {
fnptr = __builtin_ptrauth_sign_unauthenticated(fnptr, 0, ptr_discriminator);
}
-// CHECK-LABEL: define void @test_auth_and_resign()
+// CHECK-LABEL: define {{.*}}void @test_auth_and_resign()
void test_auth_and_resign() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -51,7 +52,7 @@ void test_auth_and_resign() {
fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
}
-// CHECK-LABEL: define void @test_blend_discriminator()
+// CHECK-LABEL: define {{.*}}void @test_blend_discriminator()
void test_blend_discriminator() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC:%.*]] = load i64, ptr @int_discriminator,
@@ -61,7 +62,7 @@ void test_blend_discriminator() {
int_discriminator = __builtin_ptrauth_blend_discriminator(fnptr, int_discriminator);
}
-// CHECK-LABEL: define void @test_sign_generic_data()
+// CHECK-LABEL: define {{.*}}void @test_sign_generic_data()
void test_sign_generic_data() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
@@ -72,7 +73,7 @@ void test_sign_generic_data() {
signature = __builtin_ptrauth_sign_generic_data(fnptr, ptr_discriminator);
}
-// CHECK-LABEL: define void @test_string_discriminator()
+// CHECK-LABEL: define {{.*}}void @test_string_discriminator()
void test_string_discriminator() {
// CHECK: [[X:%.*]] = alloca i32
diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c
index 3ad3d70c24e41..467ce5e02038c 100644
--- a/clang/test/Sema/ptrauth.c
+++ b/clang/test/Sema/ptrauth.c
@@ -47,6 +47,17 @@ void test_blend_discriminator(int *dp, int (*fp)(int), int value) {
float *mismatch = __builtin_ptrauth_blend_discriminator(dp, value); // expected-error {{incompatible integer to pointer conversion initializing 'float *' with an expression of type}}
}
+void test_string_discriminator(const char *str) {
+ __builtin_ptrauth_string_discriminator(); // expected-error {{too few arguments}}
+ __builtin_ptrauth_string_discriminator(str, str); // expected-error {{too many arguments}}
+ (void) __builtin_ptrauth_string_discriminator("test string"); // no warning
+
+ __builtin_ptrauth_string_discriminator(str); // expected-error {{argument must be a string literal}}
+
+ void *mismatch = __builtin_ptrauth_string_discriminator("test string"); // expected-error {{incompatible integer to pointer conversion initializing 'void *' with an expression of type 'unsigned long'}}
+}
+
+
void test_sign_unauthenticated(int *dp, int (*fp)(int)) {
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY); // expected-error {{too few arguments}}
__builtin_ptrauth_sign_unauthenticated(dp, VALID_DATA_KEY, dp, dp); // expected-error {{too many arguments}}
>From 8e7d4bc0f98ecb8b0f6eb6371d7a1ba27a976c09 Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Mon, 3 Jun 2024 13:38:23 -0700
Subject: [PATCH 4/4] Format.
---
clang/lib/Sema/SemaChecking.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b69542b9dc74d..236be292174d8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2157,7 +2157,8 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
}
static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
- if (checkPointerAuthEnabled(S, Call)) return ExprError();
+ if (checkPointerAuthEnabled(S, Call))
+ return ExprError();
// We've already performed normal call type-checking.
const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
@@ -2166,8 +2167,7 @@ static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
const auto *Literal = dyn_cast<StringLiteral>(Arg);
if (!Literal || Literal->getCharByteWidth() != 1) {
S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
- << (Literal ? 1 : 0)
- << Arg->getSourceRange();
+ << (Literal ? 1 : 0) << Arg->getSourceRange();
return ExprError();
}
More information about the llvm-branch-commits
mailing list