https://github.com/ahmedbougacha created https://github.com/llvm/llvm-project/pull/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. >From 61be7a922397d66773a8f4a6e476ea321f52f00c Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha <ah...@bougacha.org> Date: Thu, 30 May 2024 17:22:29 -0700 Subject: [PATCH] [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 <rjmcc...@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; +} _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits