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 <ah...@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;
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to