[clang] [clang] Implement type/address discrimination of type_info vtable. (PR #99726)
Ahmed Bougacha via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 19 17:37:07 PDT 2024
https://github.com/ahmedbougacha created https://github.com/llvm/llvm-project/pull/99726
We want to be able to support full type and address discrimination of type_info on targets that don't have existing ABI compatibility constraints.
This patch does not enable such behavior on any platform, it just adds the necessary machinery.
In clang we add a new commandline argument to control the type_info vtable ABI:
```
-fptrauth-type-info-vtable-pointer-discrimination
```
and a feature flag to allow source level detection of the ABI:
```
__has_feature(ptrauth_type_info_vtable_pointer_discrimination)
```
>From f46421f8e0349f65f07ab3bd822e179bf983439f Mon Sep 17 00:00:00 2001
From: Ahmed Bougacha <ahmed at bougacha.org>
Date: Wed, 17 Jul 2024 16:18:41 -0700
Subject: [PATCH] [clang] Implement type/address discrimination of type_info
vtable.
We want to be able to support full type and address discrimination
of type_info on targets that don't have existing ABI compatibility
constraints.
This patch does not enable such behavior on any platform, it just
adds the necessary machinery.
In clang we add a new commandline argument to control the type_info
vtable ABI:
-fptrauth-type-info-vtable-pointer-discrimination
and a feature flag to allow source level detection of the ABI:
__has_feature(ptrauth_type_info_vtable_pointer_discrimination)
---
clang/include/clang/Basic/Features.def | 1 +
clang/include/clang/Basic/LangOptions.def | 1 +
.../include/clang/Basic/PointerAuthOptions.h | 5 ++
clang/include/clang/Driver/Options.td | 2 +
clang/lib/Frontend/CompilerInvocation.cpp | 17 +++-
.../CodeGenCXX/ptrauth-type-info-vtable.cpp | 87 +++++++++++++++++++
6 files changed, 111 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 2f864ff1c0edf..14572bc0407fc 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -108,6 +108,7 @@ FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
+FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index a6f36b23f07dc..8b09049b5cb97 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -168,6 +168,7 @@ LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication")
LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
+LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, "incorporate type and address discrimination in authenticated vtable pointers for std::type_info")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
BENIGN_LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0,
"Use type discrimination when signing function pointers")
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
index 197d63642ca6d..6153209410843 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -25,6 +25,11 @@ namespace clang {
constexpr unsigned PointerAuthKeyNone = -1;
+/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
+/// The value is ptrauth_string_discriminator("_ZTVSt9type_info"), i.e.,
+/// the vtable type discriminator for classes derived from std::type_info.
+constexpr uint16_t StdTypeInfoVTablePointerConstantDiscrimination = 0xB1EA;
+
class PointerAuthSchema {
public:
enum class Kind : unsigned {
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 9c6cebd77ff0a..70dab1b16094d 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4249,6 +4249,8 @@ defm ptrauth_vtable_pointer_address_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">;
defm ptrauth_vtable_pointer_type_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
+defm ptrauth_type_info_vtable_pointer_discrimination :
+ OptInCC1FFlag<"ptrauth-type-info-vtable-pointer-discrimination", "Enable type and address discrimination of vtable pointer of std::type_info">;
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
defm ptrauth_function_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination",
"Enable type discrimination on C function pointers">;
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index bf57addff1c6d..424fe53990c38 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1488,8 +1488,15 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination,
LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type
: Discrimination::None);
- Opts.CXXTypeInfoVTablePointer =
- PointerAuthSchema(Key::ASDA, false, Discrimination::None);
+
+ if (LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
+ Opts.CXXTypeInfoVTablePointer =
+ PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
+ StdTypeInfoVTablePointerConstantDiscrimination);
+ else
+ Opts.CXXTypeInfoVTablePointer =
+ PointerAuthSchema(Key::ASDA, false, Discrimination::None);
+
Opts.CXXVTTVTablePointers =
PointerAuthSchema(Key::ASDA, false, Discrimination::None);
Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers =
@@ -3411,6 +3418,9 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination);
if (Opts.PointerAuthVTPtrTypeDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
+ if (Opts.PointerAuthTypeInfoVTPtrDiscrimination)
+ GenerateArg(Consumer, OPT_fptrauth_type_info_vtable_pointer_discrimination);
+
if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
if (Opts.PointerAuthFunctionTypeDiscrimination)
@@ -3427,6 +3437,9 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);
Opts.PointerAuthVTPtrTypeDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
+ Opts.PointerAuthTypeInfoVTPtrDiscrimination =
+ Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination);
+
Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
Opts.PointerAuthFunctionTypeDiscrimination =
Args.hasArg(OPT_fptrauth_function_pointer_type_discrimination);
diff --git a/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp b/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp
new file mode 100644
index 0000000000000..5fde93c309c30
--- /dev/null
+++ b/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -DENABLE_TID=0 -I%S -std=c++11 -triple=arm64e-apple-darwin \
+// RUN: -fptrauth-calls -fptrauth-intrinsics \
+// RUN: -fptrauth-vtable-pointer-type-discrimination \
+// RUN: -fptrauth-vtable-pointer-address-discrimination \
+// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NODISC
+
+// RUN: %clang_cc1 -DENABLE_TID=1 -I%S -std=c++11 -triple=arm64e-apple-darwin \
+// RUN: -fptrauth-calls -fptrauth-intrinsics \
+// RUN: -fptrauth-vtable-pointer-type-discrimination \
+// RUN: -fptrauth-vtable-pointer-address-discrimination \
+// RUN: -fptrauth-type-info-vtable-pointer-discrimination \
+// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DISC
+
+// copied from typeinfo
+namespace std {
+
+#if __has_cpp_attribute(clang::ptrauth_vtable_pointer)
+# if __has_feature(ptrauth_type_info_vtable_pointer_discrimination)
+# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
+ [[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, type_discrimination)]]
+# else
+# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
+ [[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]]
+# endif
+#else
+# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH
+#endif
+
+ class _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH type_info
+ {
+ type_info& operator=(const type_info&);
+ type_info(const type_info&);
+
+ protected:
+ explicit type_info(const char* __n);
+
+ public:
+ virtual ~type_info();
+
+ virtual void test_method();
+ };
+}
+
+static_assert(__has_feature(ptrauth_type_info_vtable_pointer_discrimination) == ENABLE_TID, "incorrect feature state");
+
+// CHECK: @disc_std_type_info = global i32 [[STDTYPEINFO_DISC:45546]]
+extern "C" int disc_std_type_info = __builtin_ptrauth_string_discriminator("_ZTVSt9type_info");
+
+// CHECK: @_ZTV10TestStruct = unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI10TestStruct, ptr ptrauth (ptr @_ZN10TestStructD1Ev, i32 0, i64 52216, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV10TestStruct, i32 0, i32 0, i32 2)), ptr ptrauth (ptr @_ZN10TestStructD0Ev, i32 0, i64 39671, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV10TestStruct, i32 0, i32 0, i32 3))] }, align 8
+// CHECK: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
+// CHECK: @_ZTS10TestStruct = constant [13 x i8] c"10TestStruct\00", align 1
+
+// NODISC: @_ZTI10TestStruct = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr @_ZTS10TestStruct }, align 8
+
+// DISC: @_ZTI10TestStruct = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2, i64 [[STDTYPEINFO_DISC]]), ptr @_ZTS10TestStruct }, align 8
+
+struct TestStruct {
+ virtual ~TestStruct();
+ int a;
+};
+
+TestStruct::~TestStruct(){}
+
+extern "C" void test_vtable(std::type_info* t) {
+ t->test_method();
+}
+// NODISC: define void @test_vtable(ptr noundef %t)
+// NODISC: [[T_ADDR:%.*]] = alloca ptr, align 8
+// NODISC: store ptr %t, ptr [[T_ADDR]], align 8
+// NODISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
+// NODISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8
+// NODISC: [[CAST_VPTR:%.*]] = ptrtoint ptr [[VPTR]] to i64
+// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VPTR]], i32 2, i64 0)
+
+// DISC: define void @test_vtable(ptr noundef %t)
+// DISC: [[T_ADDR:%.*]] = alloca ptr, align 8
+// DISC: store ptr %t, ptr [[T_ADDR]], align 8
+// DISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
+// DISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8
+// DISC: [[ADDR:%.*]] = ptrtoint ptr [[T]] to i64
+// DISC: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 [[STDTYPEINFO_DISC]])
+// DISC: [[VPTRI:%.*]] = ptrtoint ptr [[VPTR]] to i64
+// DISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VPTRI]], i32 2, i64 [[DISCRIMINATOR]])
+
+extern "C" const void *ensure_typeinfo() {
+ return new TestStruct;
+}
More information about the cfe-commits
mailing list