Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][libc++abi] Minor follow-up changes after ptrauth upstreaming #87481

Merged
merged 5 commits into from
Jul 23, 2024

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented Apr 3, 2024

This patch applies the comments provided on #84573. This is done as a separate PR to avoid merge conflicts with downstreams that already had ptrauth support.

libcxx/include/typeinfo Outdated Show resolved Hide resolved
Copy link

github-actions bot commented Apr 3, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@ldionne ldionne added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Apr 3, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Apr 3, 2024

@llvm/pr-subscribers-libcxxabi

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

This patch applies the comments provided on #84573. This is done as a separate PR to avoid merge conflicts with downstreams that already had ptrauth support.


Full diff: https://github.com/llvm/llvm-project/pull/87481.diff

3 Files Affected:

  • (modified) libcxx/include/typeinfo (+1-1)
  • (modified) libcxx/src/include/overridable_function.h (+3-3)
  • (modified) libcxxabi/src/private_typeinfo.cpp (+8-15)
diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo
index d1c0de3c1bfdd3..76320c33c692e7 100644
--- a/libcxx/include/typeinfo
+++ b/libcxx/include/typeinfo
@@ -275,7 +275,7 @@ struct __type_info_implementations {
           __impl;
 };
 
-#    if defined(__arm64__) && __has_cpp_attribute(clang::ptrauth_vtable_pointer)
+#    if __has_cpp_attribute(clang::ptrauth_vtable_pointer)
 #      if __has_feature(ptrauth_type_info_discriminated_vtable_pointer)
 #        define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH                                                                  \
           [[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, type_discrimination)]]
diff --git a/libcxx/src/include/overridable_function.h b/libcxx/src/include/overridable_function.h
index fca66ea6daf7a8..2f590483a9023c 100644
--- a/libcxx/src/include/overridable_function.h
+++ b/libcxx/src/include/overridable_function.h
@@ -13,7 +13,7 @@
 #include <__config>
 #include <cstdint>
 
-#if defined(__arm64e__) && __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls)
 #  include <ptrauth.h>
 #endif
 
@@ -85,13 +85,13 @@ _LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) no
   uintptr_t __end   = reinterpret_cast<uintptr_t>(&__lcxx_override_end);
   uintptr_t __ptr   = reinterpret_cast<uintptr_t>(__fptr);
 
-#if defined(__arm64e__) && __has_feature(ptrauth_calls)
+#  if __has_feature(ptrauth_calls)
   // We must pass a void* to ptrauth_strip since it only accepts a pointer type. Also, in particular,
   // we must NOT pass a function pointer, otherwise we will strip the function pointer, and then attempt
   // to authenticate and re-sign it when casting it to a uintptr_t again, which will fail because we just
   // stripped the function pointer. See rdar://122927845.
   __ptr = reinterpret_cast<uintptr_t>(ptrauth_strip(reinterpret_cast<void*>(__ptr), ptrauth_key_function_pointer));
-#endif
+#  endif
 
   // Finally, the function was overridden if it falls outside of the section's bounds.
   return __ptr < __start || __ptr > __end;
diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index 9e58501a559342..2fbfa526afc0ec 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -55,15 +55,12 @@
 #include <ptrauth.h>
 #endif
 
-
-template<typename T>
-static inline
-T *
-get_vtable(T *vtable) {
+template <typename T>
+static inline T* strip_vtable(T* vtable) {
 #if __has_feature(ptrauth_calls)
-    vtable = ptrauth_strip(vtable, ptrauth_key_cxx_vtable_pointer);
+  vtable = ptrauth_strip(vtable, ptrauth_key_cxx_vtable_pointer);
 #endif
-    return vtable;
+  return vtable;
 }
 
 static inline
@@ -117,8 +114,7 @@ void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr
         reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;
     info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
 #else
-    void **vtable = *static_cast<void ** const *>(static_ptr);
-    vtable = get_vtable(vtable);
+    void **vtable = strip_vtable(*static_cast<void ** const *>(static_ptr));
     info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
     info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
     info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
@@ -576,8 +572,7 @@ __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
        find the layout.  */
     offset_to_base = __offset_flags >> __offset_shift;
     if (is_virtual) {
-      const char* vtable = *static_cast<const char* const*>(adjustedPtr);
-      vtable = get_vtable(vtable);
+      const char* vtable = strip_vtable(*static_cast<const char* const*>(adjustedPtr));
       offset_to_base = update_offset_to_base(vtable, offset_to_base);
     }
   } else if (!is_virtual) {
@@ -1517,8 +1512,7 @@ __base_class_type_info::search_above_dst(__dynamic_cast_info* info,
     ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
     if (__offset_flags & __virtual_mask)
     {
-        const char* vtable = *static_cast<const char*const*>(current_ptr);
-        vtable = get_vtable(vtable);
+        const char* vtable = strip_vtable(*static_cast<const char*const*>(current_ptr));
         offset_to_base = update_offset_to_base(vtable, offset_to_base);
     }
     __base_type->search_above_dst(info, dst_ptr,
@@ -1538,8 +1532,7 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info,
     ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
     if (__offset_flags & __virtual_mask)
     {
-        const char* vtable = *static_cast<const char*const*>(current_ptr);
-        vtable = get_vtable(vtable);
+        const char* vtable = strip_vtable(*static_cast<const char*const*>(current_ptr));
         offset_to_base = update_offset_to_base(vtable, offset_to_base);
     }
     __base_type->search_below_dst(info,

@ldionne ldionne added the libc++abi libc++abi C++ Runtime Library. Not libc++. label Apr 3, 2024
@@ -275,7 +275,7 @@ struct __type_info_implementations {
__impl;
};

# if defined(__arm64__) && __has_cpp_attribute(clang::ptrauth_vtable_pointer)
# if __has_cpp_attribute(clang::ptrauth_vtable_pointer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be _Uglified. Also, why is this not in __config?

Copy link
Member Author

@ldionne ldionne Apr 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is only used for std::type_info, I feel it makes more sense to keep this macro localized to <typeinfo>. If we used it elsewhere then it would make more sense to lift it to __config. WDYT?

Regarding uglifying, the right spelling would be __has_cpp_attribute(_Clang::__ptrauth_vtable_pointer__) and we can also change e.g. __has_feature(__ptrauth_type_info_discriminated_vtable_pointer__), right?

Comment on lines 278 to 280
# if __has_cpp_attribute(_Clang::__ptrauth_vtable_pointer__) && __has_feature(__ptrauth_calls__)
# if __has_feature(__ptrauth_vtable_address_discrimination__) || \
__has_feature(__ptrauth_vtable_type_discrimination__)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahmedbougacha @asl @kovdan01

Do these conditions seem right to you? This is important to get right since it's ABI affecting.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A different signing schema is used for type info vtable pointers compared to other vtable pointers: see https://github.com/ahmedbougacha/llvm-project/blob/eng/arm64e-upstream-llvmorg/clang/include/clang/Basic/PointerAuthOptions.h#L246 (also see a comment in code for context). The reason is that in ItaniumRTTIBuilder::BuildVTablePointer, we only have mangled names of classes derived from std::type_info, and do not have full definitions with info about base class. So, we can't use type-dependent extra discrimination, since for vtable pointers, it relies on ability to look up base class definition. As for address discrimination for type_info-related vtable pointers, it could probably be supported on clang side, but it currently isn't.

Given that, in libcxx, previously, we unconditionally disabled type-based and address discrimination for type info vtable pointers. Here is the condition we used in downstream:

#if (defined(__arm64__) || defined(__aarch64__)) && \
    __has_feature(ptrauth_calls) && \
    __has_cpp_attribute(clang::ptrauth_vtable_pointer)
#define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
   [[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]]
#else
#define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH
#endif

I see that now type-based and address discrimination are enabled in libcxx under certain conditions: see https://github.com/ahmedbougacha/llvm-project/blob/eng/arm64e-upstream-llvmorg/libcxx/include/typeinfo#L278

#    if defined(__arm64__) && __has_cpp_attribute(clang::ptrauth_vtable_pointer)
#      if __has_feature(ptrauth_type_info_discriminated_vtable_pointer)
#        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

@ahmedbougacha I was unable to find any information about ptrauth_type_info_discriminated_vtable_pointer preprocessor feature in your branch (except its usage in include/typeinfo in libcxx). I also do not see any changes related to additional discrimination in initialization of CXXTypeInfoVTablePointer field of class PointerAuthOptions. It looks like there are no related changes in ItaniumRTTIBuilder::BuildVTablePointer as well. Please let me know if non-zero discrimination is actually supported on clang side for type info vtable pointers?

@ahmedbougacha @asl @ldionne I think there are 3 questions we need to answer to construct a condition everyone likes.

  1. Do we want to check target architecture? If so, both __arm64__ and __aarch64__ should be checked. I'd prefer to have this check - even though it's probably redundant since other ptrauth-related checks are true only on aarch64, IMHO for those who don't know all the context it might be useful to see the architecture name and know that "OK, it's aarch64-specific stuff".

  2. Do we want to check ptrauth_calls preprocessor feature enabled? I'd prefer to have this check - it's probably also redundant since [[clang::ptrauth_vtable_pointer]] attribute should have no effect w/o ptrauth_calls preprocessor feature, but, again, more verbosity might be useful for those who reads the code.

  3. Do we want to allow type-based and/or address discrimination for type info vtable pointers? If so, what's the condition for that? Check against __has_feature(ptrauth_type_info_discriminated_vtable_pointer) like in @ahmedbougacha 's branch, or smth else?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ldionne @ahmedbougacha @asl
Update. My preference is the following:

  1. Do not check arm64/aarch64. If in future we have ptrauth support on non-arm64, for example, via soft pointer auth, the conditions will remain the same. Since we don't have different logic for ptrauth+non-arm64, no need for additional check.
  2. Do not check against ptrauth_calls. The [[clang::ptrauth_vtable_pointer]] attribute has no effect w/o ptrauth_calls enabled.
  3. If we want to introduce __has_feature(ptrauth_type_info_discriminated_vtable_pointer), @ahmedbougacha please update your branch to include changes allowing such discrimination - now there is no support on clang side.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we shouldn't do this change here, it does the opposite of what we want: the ptrauth (current arm64e, or elf pauthabi) ABI does sign vtable pointers with type/address discrimination. But it specifically doesn't sign the type info vtable pointer, which is why we need this special annotation, to override the default vtable ptr discrimination (that's exposed with the ptrauth_vtable_address_discrimination/ptrauth_vtable_type_discrimination features) to match the type info vtable codegen.

Since then we have indeed added support for signing these, and that's indeed denoted by ptrauth_type_info_discriminated_vtable_pointer. So I think the version that's in tree today is doing the right thing, and honoring clang's directive given its understanding of the ABI. (I don't mind and I'm not worried about removing the arm64 check FWIW).

We'll open a clang PR to add ptrauth_type_info_discriminated_vtable_pointer. But looking at it now I think we'll want to rename it first, so let's settle that this week before it's too late (cc @ojhunt)

@kovdan01 to answer your specific questions: in general I do think these should check something else than ptrauth features, because the specific decisions are made by a specific platform ABI, and isn't set in stone for all ptrauth. Concretely, for the soft ptrauth example, a real soft ptrauth implementation could very well force these to be always discriminated, and use a different key (soft ptrauth not being constrained by HW keys, it uses a different key for every single ABI usage; it could use one for "type info vtable ptrs").
In practice there likely won't ever be a serious and meaningfully different ptrauth ABI, so this doesn't seem like a real problem either way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahmedbougacha As far as I understood, you are OK with current implementation present in this PR. It enables type+address discrimination for type info vtable pointers when we have __has_feature(__ptrauth_vtable_address_discrimination__) || __has_feature(__ptrauth_vtable_type_discrimination__). Is this really the thing we want to? I'm a bit concerned with this since I've never seen support for discriminating type info vtable pointers (although I understand that you have that already), and the condition present in the PR will enable such discrimination while mainline clang does not support that yet.

Previously, the condition was __has_feature(ptrauth_type_info_discriminated_vtable_pointer), and I think it's better since it does not affect type info vtable pointers discrimination unless it's really implemented on clang side.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, the condition was __has_feature(ptrauth_type_info_discriminated_vtable_pointer), and I think it's better since it does not affect type info vtable pointers discrimination unless it's really implemented on clang side.

Yes, to be clear I agree that's what's best

@ldionne ldionne added this to the LLVM 19.X Release milestone Jul 18, 2024
@ldionne
Copy link
Member Author

ldionne commented Jul 23, 2024

I believe I have applied all the comments. I will merge this once CI is green and I will cherry-pick this back to the LLVM 19 release branch.

@ldionne
Copy link
Member Author

ldionne commented Jul 23, 2024

Only the FreeBSD job hasn't finished yet and it won't bring additional signal for this change, merging now.

@ldionne ldionne merged commit e64e745 into llvm:main Jul 23, 2024
52 of 54 checks passed
@ldionne ldionne deleted the review/ptrauth-followups branch July 23, 2024 18:04
@ldionne
Copy link
Member Author

ldionne commented Jul 23, 2024

/cherry-pick e64e745

@llvmbot
Copy link
Collaborator

llvmbot commented Jul 23, 2024

Failed to cherry-pick: e64e745

https://github.com/llvm/llvm-project/actions/runs/10064019269

Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request

@ldionne
Copy link
Member Author

ldionne commented Jul 23, 2024

/cherry-pick e64e745

llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Jul 23, 2024
…llvm#87481)

This patch applies the comments provided on llvm#84573. This is done as a
separate PR to avoid merge conflicts with downstreams that already had
ptrauth support.

(cherry picked from commit e64e745)
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 23, 2024

/pull-request #100183

yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
…#87481)

Summary:
This patch applies the comments provided on #84573. This is done as a
separate PR to avoid merge conflicts with downstreams that already had
ptrauth support.

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60251081
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Jul 29, 2024
…llvm#87481)

This patch applies the comments provided on llvm#84573. This is done as a
separate PR to avoid merge conflicts with downstreams that already had
ptrauth support.

(cherry picked from commit e64e745)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++abi libc++abi C++ Runtime Library. Not libc++. libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

5 participants