[clang] [PAuth] Use different discriminators for __int128_t / __uint128_t / _BitInt(n) (PR #140276)
Anton Korobeynikov via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 1 23:56:01 PDT 2025
https://github.com/asl updated https://github.com/llvm/llvm-project/pull/140276
>From 21d2b2da72d9e8f3994cb913a86c093212bb8711 Mon Sep 17 00:00:00 2001
From: Anton Korobeynikov <anton at korobeynikov.info>
Date: Fri, 16 May 2025 19:25:57 +0300
Subject: [PATCH 1/2] [PAuth] Use different discriminators for __int128_t /
__uint128_t / _BitInt(n) compared to other integer types when computing
function pointer type discriminator.
These parameter types have different parameter passing ABI as compared to
ordinary integer types (e.g. require 2 registers instead of 1) and therefore
this parameter passing difference could potentially be exploited should function
pointer is substituted.
---
clang/lib/AST/ASTContext.cpp | 14 ++++++---
.../ptrauth-function-type-discriminator.c | 31 +++++++++++++++++++
2 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 5044d7c33ec3c..3991c67036576 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3395,21 +3395,27 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
// Don't bother discriminating based on these types.
case Type::Pipe:
- case Type::BitInt:
case Type::ConstantMatrix:
OS << "?";
return;
+ case Type::BitInt: {
+ const auto *BtTy = T->castAs<BitIntType>();
+ OS << "D" << (BtTy->isUnsigned() ? "U" : "B") << BtTy->getNumBits() << "_";
+ return;
+ }
+
case Type::Builtin: {
const auto *BTy = T->castAs<BuiltinType>();
- switch (BTy->getKind()) {
+ const auto Kind = BTy->getKind();
+ switch (Kind) {
#define SIGNED_TYPE(Id, SingletonId) \
case BuiltinType::Id: \
- OS << "i"; \
+ OS << (Kind == BuiltinType::Int128 ? "n" : "i"); \
return;
#define UNSIGNED_TYPE(Id, SingletonId) \
case BuiltinType::Id: \
- OS << "i"; \
+ OS << (Kind == BuiltinType::UInt128 ? "o" : "i"); \
return;
#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
#define BUILTIN_TYPE(Id, SingletonId)
diff --git a/clang/test/CodeGen/ptrauth-function-type-discriminator.c b/clang/test/CodeGen/ptrauth-function-type-discriminator.c
index 0952c1abf6c07..9bf4a8874c3c3 100644
--- a/clang/test/CodeGen/ptrauth-function-type-discriminator.c
+++ b/clang/test/CodeGen/ptrauth-function-type-discriminator.c
@@ -65,6 +65,37 @@ void (*fptr3)(void) = __builtin_ptrauth_sign_constant(&external_function, 2, 26)
// CHECK: @fptr4 = global ptr ptrauth (ptr @external_function, i32 2, i64 26, ptr @fptr4)
void (*fptr4)(void) = __builtin_ptrauth_sign_constant(&external_function, 2, __builtin_ptrauth_blend_discriminator(&fptr4, 26));
+extern void external_function_int(int);
+extern void external_function_char(char);
+extern void external_function_i128(__int128_t);
+extern void external_function_u128(__uint128_t);
+extern void external_function_b128(_BitInt(128));
+extern void external_function_b8(_BitInt(8));
+
+// Check discriminators of functions taking integer type arguments:
+
+// - Builtin integer types should be discriminated equally (so, pointer to
+// function taking int argument should accept function taking char argument
+// - _BitInt types are guaranteed distinct and therefore should be discriminated
+// differently
+// - __int128_t / __uint128_t are passed differently than char / int / long
+// (require two registers instead of one) and therefore should be discriminated
+// differently.
+
+// CHECK: @fptr5 = global ptr ptrauth (ptr @external_function_int, i32 0, i64 2712)
+// CHECK: @fptr6 = global ptr ptrauth (ptr @external_function_char, i32 0, i64 2712)
+void (*fptr5)(int) = external_function_int;
+void (*fptr6)(char) = external_function_char;
+
+// CHECK: @fptr7 = global ptr ptrauth (ptr @external_function_i128, i32 0, i64 23141)
+// CHECK: @fptr8 = global ptr ptrauth (ptr @external_function_u128, i32 0, i64 45743)
+// CHECK: @fptr9 = global ptr ptrauth (ptr @external_function_b128, i32 0, i64 17854)
+// CHECK: @fptr10 = global ptr ptrauth (ptr @external_function_b8, i32 0, i64 26383)
+void (*fptr7)(__int128_t) = external_function_i128;
+void (*fptr8)(__uint128_t) = external_function_u128;
+void (*fptr9)(_BitInt(128)) = external_function_b128;
+void (*fptr10)(_BitInt(8)) = external_function_b8;
+
// CHECK-LABEL: define{{.*}} void @test_call()
void test_call() {
// CHECK: [[T0:%.*]] = load ptr, ptr @fnptr,
>From f89e872d240bd7f926d88b29741826643ed6c611 Mon Sep 17 00:00:00 2001
From: Anton Korobeynikov <anton at korobeynikov.info>
Date: Sun, 1 Jun 2025 23:55:32 -0700
Subject: [PATCH 2/2] Make type discrimination of 128-bit types optional
---
clang/include/clang/Basic/Features.def | 1 +
clang/include/clang/Basic/LangOptions.def | 2 ++
clang/include/clang/Driver/Options.td | 2 ++
clang/lib/AST/ASTContext.cpp | 18 ++++++++-----
clang/lib/Driver/ToolChains/Clang.cpp | 3 +++
clang/lib/Frontend/CompilerInvocation.cpp | 4 +++
.../ptrauth-function-type-discriminator.c | 26 ++++++++++++-------
7 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 14bff8a68846d..bff96e74e2ccb 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -119,6 +119,7 @@ FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination)
FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT)
+FEATURE(ptrauth_function_pointer_type_discrimination_128, LangOpts.PointerAuthFunctionTypeDiscrimination128)
EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 789761c1f3647..048e121a704ef 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -172,6 +172,8 @@ LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discriminati
LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, "incorporate type and address discrimination in authenticated vtable pointers for std::type_info")
BENIGN_LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0,
"Use type discrimination when signing function pointers")
+LANGOPT(PointerAuthFunctionTypeDiscrimination128, 1, 1,
+ "Use different discriminators for __int128_t / __uint128_t / _BitInt(n) compared to other integer types when computing function pointer type discriminator")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0,
"incorporate address discrimination in authenticated function pointers in init/fini arrays")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 5ca31c253ed8f..fad23fd8ab04e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4451,6 +4451,8 @@ defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini
"Enable address discrimination of function pointers in init/fini arrays">;
defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication of pointers from GOT (ELF only)">;
defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening", "Use hardened lowering for jump-table dispatch">;
+defm ptrauth_disable_128bit_type_discrimination : OptInCC1FFlag<"ptrauth-disable-128bit-type-discrimination",
+ "Do not use different discriminators for __int128_t / __uint128_t / _BitInt(n) compared to other integer types when computing function pointer type discriminator">;
}
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 3991c67036576..cdf239e379339 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3399,11 +3399,13 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
OS << "?";
return;
- case Type::BitInt: {
- const auto *BtTy = T->castAs<BitIntType>();
- OS << "D" << (BtTy->isUnsigned() ? "U" : "B") << BtTy->getNumBits() << "_";
+ case Type::BitInt:
+ if (Ctx.getLangOpts().PointerAuthFunctionTypeDiscrimination128) {
+ const auto *BtTy = T->castAs<BitIntType>();
+ OS << "D" << (BtTy->isUnsigned() ? "U" : "B") << BtTy->getNumBits() << "_";
+ } else
+ OS << "?";
return;
- }
case Type::Builtin: {
const auto *BTy = T->castAs<BuiltinType>();
@@ -3411,11 +3413,15 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
switch (Kind) {
#define SIGNED_TYPE(Id, SingletonId) \
case BuiltinType::Id: \
- OS << (Kind == BuiltinType::Int128 ? "n" : "i"); \
+ OS << (Kind == BuiltinType::Int128 && \
+ Ctx.getLangOpts().PointerAuthFunctionTypeDiscrimination128 ? \
+ "n" : "i"); \
return;
#define UNSIGNED_TYPE(Id, SingletonId) \
case BuiltinType::Id: \
- OS << (Kind == BuiltinType::UInt128 ? "o" : "i"); \
+ OS << (Kind == BuiltinType::UInt128 && \
+ Ctx.getLangOpts().PointerAuthFunctionTypeDiscrimination128 ? \
+ "o" : "i"); \
return;
#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
#define BUILTIN_TYPE(Id, SingletonId)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 13842b8cc2870..3ba4c702994bd 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1883,6 +1883,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_function_pointer_type_discrimination,
options::OPT_fno_ptrauth_function_pointer_type_discrimination);
+ Args.addOptInFlag(
+ CmdArgs, options::OPT_fptrauth_disable_128bit_type_discrimination,
+ options::OPT_fno_ptrauth_disable_128bit_type_discrimination);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
options::OPT_fno_ptrauth_indirect_gotos);
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 2c02719121c73..dd24ba7ff8dcb 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3544,6 +3544,8 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_fptrauth_type_info_vtable_pointer_discrimination);
if (Opts.PointerAuthFunctionTypeDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_function_pointer_type_discrimination);
+ if (!Opts.PointerAuthFunctionTypeDiscrimination128)
+ GenerateArg(Consumer, OPT_fptrauth_disable_128bit_type_discrimination);
if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
if (Opts.PointerAuthInitFiniAddressDiscrimination)
@@ -3569,6 +3571,8 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination);
Opts.PointerAuthFunctionTypeDiscrimination =
Args.hasArg(OPT_fptrauth_function_pointer_type_discrimination);
+ Opts.PointerAuthFunctionTypeDiscrimination128 =
+ !Args.hasArg(OPT_fptrauth_disable_128bit_type_discrimination);
Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
Opts.PointerAuthInitFiniAddressDiscrimination =
Args.hasArg(OPT_fptrauth_init_fini_address_discrimination);
diff --git a/clang/test/CodeGen/ptrauth-function-type-discriminator.c b/clang/test/CodeGen/ptrauth-function-type-discriminator.c
index 9bf4a8874c3c3..6c5c3bb0d2dd5 100644
--- a/clang/test/CodeGen/ptrauth-function-type-discriminator.c
+++ b/clang/test/CodeGen/ptrauth-function-type-discriminator.c
@@ -1,18 +1,20 @@
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
-// RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC %s
+// RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC,CHECK128 %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
-// RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefix=CHECK %s
+// RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefixes=CHECK,CHECK128 %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-pch %s -o %t.ast
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
-// RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC %s
+// RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC,CHECK128 %s
+// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
+// RUN: -fptrauth-disable-128bit-type-discrimination -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC,CHECKNO128 %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
-// RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC %s
+// RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC,CHECK128 %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
-// RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefix=CHECK %s
+// RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefixes=CHECK,CHECK128 %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-pch %s -o %t.ast
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
-// RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC %s
+// RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC,CHECK128 %s
#ifdef __cplusplus
extern "C" {
@@ -87,10 +89,14 @@ extern void external_function_b8(_BitInt(8));
void (*fptr5)(int) = external_function_int;
void (*fptr6)(char) = external_function_char;
-// CHECK: @fptr7 = global ptr ptrauth (ptr @external_function_i128, i32 0, i64 23141)
-// CHECK: @fptr8 = global ptr ptrauth (ptr @external_function_u128, i32 0, i64 45743)
-// CHECK: @fptr9 = global ptr ptrauth (ptr @external_function_b128, i32 0, i64 17854)
-// CHECK: @fptr10 = global ptr ptrauth (ptr @external_function_b8, i32 0, i64 26383)
+// CHECK128: @fptr7 = global ptr ptrauth (ptr @external_function_i128, i32 0, i64 23141)
+// CHECK128: @fptr8 = global ptr ptrauth (ptr @external_function_u128, i32 0, i64 45743)
+// CHECK128: @fptr9 = global ptr ptrauth (ptr @external_function_b128, i32 0, i64 17854)
+// CHECK128: @fptr10 = global ptr ptrauth (ptr @external_function_b8, i32 0, i64 26383)
+// CHECKNO128: @fptr7 = global ptr ptrauth (ptr @external_function_i128, i32 0, i64 2712)
+// CHECKNO128: @fptr8 = global ptr ptrauth (ptr @external_function_u128, i32 0, i64 2712)
+// CHECKNO128: @fptr9 = global ptr ptrauth (ptr @external_function_b128, i32 0, i64 41228)
+// CHECKNO128: @fptr10 = global ptr ptrauth (ptr @external_function_b8, i32 0, i64 41228)
void (*fptr7)(__int128_t) = external_function_i128;
void (*fptr8)(__uint128_t) = external_function_u128;
void (*fptr9)(_BitInt(128)) = external_function_b128;
More information about the cfe-commits
mailing list