Skip to content

Conversation

ojhunt
Copy link
Contributor

@ojhunt ojhunt commented Jun 7, 2025

This hardens the unwinding logic and datastructures on systems
that support pointer authentication.

The approach taken to hardening is to harden the schemas of as many
high value fields in the myriad structs as possible, and then also
explicitly qualify local variables referencing privileged or security
critical values.

This does introduce ABI linkage between libcxx, libcxxabi, and
libunwind but those are in principle separate from the OS itself
so we've kept the schema definitions in the library specific headers
rather than ptrauth.h

@ojhunt ojhunt requested review from asl, ahmedbougacha and ldionne June 7, 2025 02:10
@ojhunt ojhunt requested review from a team as code owners June 7, 2025 02:10
@ojhunt ojhunt added compiler-rt libc++abi libc++abi C++ Runtime Library. Not libc++. libunwind hardening Issues related to the hardening effort labels Jun 7, 2025
@llvmbot llvmbot added compiler-rt:builtins PGO Profile Guided Optimizations labels Jun 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 7, 2025

@llvm/pr-subscribers-pgo
@llvm/pr-subscribers-libcxxabi

@llvm/pr-subscribers-libunwind

Author: Oliver Hunt (ojhunt)

Changes

This hardens the unwinding logic and datastructures on systems that support pointer authentication.

The approach taken to hardening is to harden the schemas of as many high value fields in the myriad structs as possible, and then also explicitly qualify local variables referencing privileged or security critical values.

This ABI is exposed to the personality functions, and so updating to conform to that is a mandatory change, but to reduce the risk of oracles, the adoption also hardened the locals and datastructures in compiler-rt and libcxxabi.

We're gating these on defined(__APPLE__) so other platforms are able to qualify before enabling. An alternative would be an feature flag that could be used instead but I didn't want to force such a change if it was not considered
necessary.


Patch is 51.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/143230.diff

14 Files Affected:

  • (modified) compiler-rt/lib/builtins/gcc_personality_v0.c (+63-6)
  • (modified) compiler-rt/lib/profile/InstrProfilingValue.c (+7-1)
  • (modified) libcxxabi/include/__cxxabi_config.h (+47-1)
  • (modified) libcxxabi/src/cxa_exception.h (+16-14)
  • (modified) libcxxabi/src/cxa_personality.cpp (+61-8)
  • (modified) libunwind/include/libunwind.h (+70-8)
  • (modified) libunwind/src/AddressSpace.hpp (+30-14)
  • (modified) libunwind/src/DwarfInstructions.hpp (+8-3)
  • (modified) libunwind/src/DwarfParser.hpp (+40-4)
  • (modified) libunwind/src/Registers.hpp (+109-4)
  • (modified) libunwind/src/UnwindCursor.hpp (+55-17)
  • (modified) libunwind/src/UnwindLevel1.c (+30-6)
  • (modified) libunwind/src/UnwindRegistersSave.S (+10)
  • (modified) libunwind/src/libunwind.cpp (+34)
diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
index ef63a5fb83472..42b992949d2cc 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -30,6 +30,45 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
                                             _Unwind_Personality_Fn);
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       \
+                                              discriminatorString)             \
+    __ptrauth_restricted_intptr(key, addressDiscriminated,                     \
+                            ptrauth_string_discriminator(discriminatorString))
+#else
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       \
+                                              discriminatorString)             \
+    __ptrauth(key, addressDiscriminated,                                       \
+              ptrauth_string_discriminator(discriminatorString))
+#endif
+#else
+#define PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(key, addressDiscriminated,       \
+                                              discriminatorString)
+#endif
+
+// Helper wrappers for pointer auth qualifiers because we use a lot of variants
+// Suffixes:
+//  * PDC : ptrauth_key_process_dependent_code
+//  * RA  : ptrauth_key_return_address
+//  * FN  : ptrauth_key_function_pointer
+#define PERSONALITY_PTRAUTH_RI_FN(__discriminator)                             \
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_function_pointer,        \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define PERSONALITY_PTRAUTH_RI_PDC(__discriminator)                            \
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_code,  \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define PERSONALITY_PTRAUTH_RI_RA(__discriminator)                             \
+    PERSONALITY_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_return_address,          \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+
 // Pointer encodings documented at:
 //   http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
 
@@ -205,7 +244,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
     return continueUnwind(exceptionObject, context);
 
   uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
-  uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
+  uintptr_t PERSONALITY_PTRAUTH_RI_FN("__gcc_personality_v0'funcStart")
+      funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
   uintptr_t pcOffset = pc - funcStart;
 
   // Parse LSDA header.
@@ -224,11 +264,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
   const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
   const uint8_t *p = callSiteTableStart;
   while (p < callSiteTableEnd) {
-    uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
-    size_t length = readEncodedPointer(&p, callSiteEncoding);
-    size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+    uintptr_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'start")
+        start = readEncodedPointer(&p, callSiteEncoding);
+    size_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'length")
+        length = readEncodedPointer(&p, callSiteEncoding);
+    size_t PERSONALITY_PTRAUTH_RI_PDC("__gcc_personality_v0'landingPadOffset")
+        landingPadOffset = readEncodedPointer(&p, callSiteEncoding);
     readULEB128(&p); // action value not used for C code
-    if (landingPad == 0)
+    if (landingPadOffset == 0)
       continue; // no landing pad for this entry
     if ((start <= pcOffset) && (pcOffset < (start + length))) {
       // Found landing pad for the PC.
@@ -238,7 +281,21 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
                     (uintptr_t)exceptionObject);
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
-      _Unwind_SetIP(context, (funcStart + landingPad));
+#define LANDING_PAD_DISCRIMINATOR "__gcc_personality_v0'landingPad"
+      size_t PERSONALITY_PTRAUTH_RI_RA(LANDING_PAD_DISCRIMINATOR)
+          landingPad = funcStart + landingPadOffset;
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+      uintptr_t stack_pointer = _Unwind_GetGR(context, -2);
+      const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
+          &landingPad,
+          ptrauth_string_discriminator(LANDING_PAD_DISCRIMINATOR));
+      uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
+          *(void **)&landingPad, ptrauth_key_function_pointer,
+          existingDiscriminator, ptrauth_key_return_address, stack_pointer);
+      _Unwind_SetIP(context, newIP);
+#else
+      _Unwind_SetIP(context, landingPad);
+#endif
       return _URC_INSTALL_CONTEXT;
     }
   }
diff --git a/compiler-rt/lib/profile/InstrProfilingValue.c b/compiler-rt/lib/profile/InstrProfilingValue.c
index a608d41d39e77..cd6ae3d7a4248 100644
--- a/compiler-rt/lib/profile/InstrProfilingValue.c
+++ b/compiler-rt/lib/profile/InstrProfilingValue.c
@@ -83,7 +83,13 @@ __llvm_profile_iterate_data(const __llvm_profile_data *Data) {
 /* This method is only used in value profiler mock testing.  */
 COMPILER_RT_VISIBILITY void *
 __llvm_get_function_addr(const __llvm_profile_data *Data) {
-  return Data->FunctionPointer;
+  void *FP = Data->FunctionPointer;
+#if __has_feature(ptrauth_calls)
+  // This is only used for tests where we compare against what happens to be
+  // signed pointers.
+  FP = ptrauth_sign_unauthenticated(FP, VALID_CODE_KEY, 0);
+#endif
+   return FP;
 }
 
 /* Allocate an array that holds the pointers to the linked lists of
diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 759445dac91f9..e67d065fe57f3 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -32,7 +32,8 @@
 #endif
 
 #if defined(_WIN32)
- #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) || (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
+ #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) ||                     \
+     (defined(__MINGW32__) && !defined(_LIBCXXABI_BUILDING_LIBRARY))
   #define _LIBCXXABI_HIDDEN
   #define _LIBCXXABI_DATA_VIS
   #define _LIBCXXABI_FUNC_VIS
@@ -109,4 +110,49 @@
 #  define _LIBCXXABI_NOEXCEPT noexcept
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#  define _LIBCXXABI_PTRAUTH(__key, __address_discriminated, __discriminator)  \
+    __ptrauth(__key,__address_discriminated,                                   \
+              ptrauth_string_discriminator(__discriminator))
+// This work around is required to support divergence in spelling
+// during the ptrauth upstreaming process.
+#  if __has_feature(ptrauth_restricted_intptr_qualifier)
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, \
+                                               __discriminator)                \
+    __ptrauth_restricted_intptr(__key,__address_discriminated,                 \
+                                ptrauth_string_discriminator(__discriminator))
+#  else
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, \
+                                               __discriminator)                \
+    __ptrauth(__key,__address_discriminated,                                   \
+              ptrauth_string_discriminator(__discriminator))
+#  endif
+#else
+#  define _LIBCXXABI_PTRAUTH(__key, __address_discriminated, __discriminator)
+#  define _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated, \
+                                               __discriminator)
+#endif
+
+// Helper wrappers for pointer auth qualifiers because we use a lot of variants
+// Suffixes:
+//  * _RI : qualifier is __ptrauth_restricted_intptr
+//  * PDD : key is ptrauth_key_process_dependent_data
+//  * FN  : key is ptrauth_key_function_pointer
+#define _LIBCXXABI_PTRAUTH_PDD(__discriminator)                                \
+    _LIBCXXABI_PTRAUTH(ptrauth_key_process_dependent_data,                     \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define _LIBCXXABI_PTRAUTH_FN(__discriminator)                                 \
+    _LIBCXXABI_PTRAUTH(ptrauth_key_function_pointer,                           \
+                       /*__address_discriminated=*/1,                          \
+                       __discriminator)
+#define _LIBCXXABI_PTRAUTH_RI_PDD(__discriminator)                             \
+    _LIBCXXABI_PTRAUTH_RESTRICTED_INTPTR(ptrauth_key_process_dependent_data,   \
+                                         /*__address_discriminated=*/1,        \
+                                         __discriminator)
+
 #endif // ____CXXABI_CONFIG_H
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index aba08f2992103..4c69d48048f02 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,10 +47,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* _LIBCXXABI_PTRAUTH_FN("__cxa_exception::exceptionDestructor") exceptionDestructor)(void*);
 #endif
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler  terminateHandler;
+    std::unexpected_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::unexpectedHandler") unexpectedHandler;
+    std::terminate_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::terminateHandler") terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void *catchTemp;
-    void *adjustedPtr;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::actionRecord") actionRecord;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::languageSpecificData") languageSpecificData;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::catchTemp") catchTemp;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::adjustedPtr") adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -79,6 +79,8 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
 // http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
 // The layout of this structure MUST match the layout of __cxa_exception, with
 // primaryException instead of referenceCount.
+// The tags used in the pointer authentication qualifiers also need to match
+// those of the corresponding members in __cxa_exception.
 struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
     void* reserve; // padding.
@@ -86,9 +88,9 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler terminateHandler;
+    void(_LIBCXXABI_DTOR_FUNC* _LIBCXXABI_PTRAUTH_FN("__cxa_exception::exceptionDestructor") exceptionDestructor)(void*);
+    std::unexpected_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::unexpectedHandler") unexpectedHandler;
+    std::terminate_handler _LIBCXXABI_PTRAUTH_FN("__cxa_exception::terminateHandler") terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -99,10 +101,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void * catchTemp;
-    void *adjustedPtr;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::actionRecord") actionRecord;
+    const unsigned char* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::languageSpecificData") languageSpecificData;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::catchTemp") catchTemp;
+    void* _LIBCXXABI_PTRAUTH_PDD("__cxa_exception::adjustedPtr") adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 5f6e75c5be19c..cbb3f46e0f55c 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -22,6 +22,12 @@
 #include "private_typeinfo.h"
 #include "unwind.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#include "libunwind.h"
+
 // TODO: This is a temporary workaround for libc++abi to recognize that it's being
 // built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION
 // in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove
@@ -527,12 +533,19 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
 namespace
 {
 
+#define _LIBCXXABI_PTRAUTH_KEY ptrauth_key_process_dependent_code
+typedef const uint8_t* _LIBCXXABI_PTRAUTH_PDD("scan_results::languageSpecificData") lsd_ptr_t;
+typedef const uint8_t* _LIBCXXABI_PTRAUTH_PDD("scan_results::actionRecord") action_ptr_t;
+#define _LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC "scan_results::landingPad"
+typedef uintptr_t _LIBCXXABI_PTRAUTH_RI_PDD(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC) landing_pad_t;
+typedef void* _LIBCXXABI_PTRAUTH_PDD(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC) landing_pad_ptr_t;
+
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
-    const uint8_t* actionRecord;         // Currently unused.  Retained to ease future maintenance.
-    const uint8_t* languageSpecificData;  // Needed only for __cxa_call_unexpected
-    uintptr_t      landingPad;   // null -> nothing found, else something found
+    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future maintenance.
+    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t landingPad;       // null -> nothing found, else something found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -541,7 +554,33 @@ struct scan_results
 };
 
 }  // unnamed namespace
+}
 
+namespace {
+// The logical model for casting authenticated function pointers makes
+// it impossible to directly cast them without breaking the authentication,
+// as a result we need this pair of helpers.
+template <typename PtrType>
+void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
+  union {
+    landing_pad_t* as_landing_pad;
+    landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  *u.as_pointer = out;
+}
+
+static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
+  union {
+    const landing_pad_t* as_landing_pad;
+    const landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  return *u.as_pointer;
+}
+} // unnamed namespace
+
+extern "C" {
 static
 void
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
@@ -557,7 +596,22 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
                 reinterpret_cast<uintptr_t>(unwind_exception));
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
                 static_cast<uintptr_t>(results.ttypeIndex));
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+  auto stack_pointer = _Unwind_GetGR(context, UNW_REG_SP);
+  // We manually re-sign the IP as the __ptrauth qualifiers cannot
+  // express the required relationship with the destination address
+  const auto existingDiscriminator = ptrauth_blend_discriminator(
+      &results.landingPad,
+      ptrauth_string_discriminator(_LIBCXXABI_PTRAUTH_SCANRESULT_LANDINGPAD_DISC));
+  unw_word_t newIP = (unw_word_t)ptrauth_auth_and_resign(*(void**)&results.landingPad,
+                                                         _LIBCXXABI_PTRAUTH_KEY,
+                                                         existingDiscriminator,
+                                                         ptrauth_key_return_address,
+                                                         stack_pointer);
+  _Unwind_SetIP(context, newIP);
+#else
   _Unwind_SetIP(context, results.landingPad);
+#endif
 }
 
 /*
@@ -691,12 +745,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
         // The call sites are ordered in increasing value of start
         uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
-        uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
+        landing_pad_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if ((start <= ipOffset) && (ipOffset < (start + length)))
 #else  // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
         // ip is 1-based index into this table
-        uintptr_t landingPad = readULEB128(&callSitePtr);
+        landing_pad_t landingPad = readULEB128(&callSitePtr);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if (--ip == 0)
 #endif // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
@@ -935,8 +989,7 @@ __gxx_personality_v0
         results.ttypeIndex = exception_header->handlerSwitchValue;
         results.actionRecord = exception_header->actionRecord;
         results.languageSpecificData = exception_header->languageSpecificData;
-        results.landingPad =
-            reinterpret_cast<uintptr_t>(exception_header->catchTemp);
+        set_landing_pad_as_ptr(results, exception_header->catchTemp);
         results.adjustedPtr = exception_header->adjustedPtr;
 
         // Jump to the handler.
@@ -970,7 +1023,7 @@ __gxx_personality_v0
             exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
             exc->actionRecord = results.actionRecord;
             exc->languageSpecificData = results.languageSpecificData;
-            exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
+            exc->catchTemp = get_landing_pad_as_ptr(results);
             exc->adjustedPtr = results.adjustedPtr;
 #ifdef __WASM_EXCEPTIONS__
             // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index b2dae8feed9a3..e7375bbca1b3d 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -43,6 +43,61 @@
   #define LIBUNWIND_AVAIL
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
+#if defined(__APPLE__) && __has_feature(ptrauth_qualifier)
+#define _LIBUNWIND_PTRAUTH(__key, __address_discriminated, __discriminator)    \
+  __ptrauth(__key, __address_discriminated,                                    \
+            ptrauth_string_discriminator(__discriminator))
+// This work around is required to support divergence in spelling
+// developed during the ptrauth upstreaming process.
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define _LIBUNWIND_PTRAUTH_RESTRICTED_INTPTR(__key, __address_discriminated,   \
+                                             __discriminator)                  \
+  __ptrauth_restricted_intptr(__key, __address_discriminated,                  \
+             ptrauth_string_discriminator(__discriminator...
[truncated]

Copy link

github-actions bot commented Jun 7, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff origin/main HEAD --extensions c,cpp,hpp,h -- compiler-rt/lib/builtins/gcc_personality_v0.c libcxxabi/include/__cxxabi_config.h libcxxabi/src/cxa_exception.cpp libcxxabi/src/cxa_exception.h libcxxabi/src/cxa_personality.cpp libunwind/include/__libunwind_config.h libunwind/include/libunwind.h libunwind/src/AddressSpace.hpp libunwind/src/CompactUnwinder.hpp libunwind/src/DwarfInstructions.hpp libunwind/src/DwarfParser.hpp libunwind/src/Registers.hpp libunwind/src/UnwindCursor.hpp libunwind/src/UnwindLevel1.c libunwind/src/libunwind.cpp

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from clang-format here.
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index fa4c4dc55..9c495e668 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,7 +47,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
 #endif
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
@@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
-    const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
-    void *__ptrauth_cxxabi_catch_temp catchTemp;
-    void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
+    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
+    void* __ptrauth_cxxabi_catch_temp catchTemp;
+    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -88,7 +88,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
 
@@ -101,10 +101,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
-    const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
-    void *__ptrauth_cxxabi_catch_temp catchTemp;
-    void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
+    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
+    void* __ptrauth_cxxabi_catch_temp catchTemp;
+    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index b7eb0f23d..b2168067a 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -567,17 +567,17 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
 namespace
 {
 
-typedef const uint8_t *__ptrauth_scan_results_lsd lsd_ptr_t;
-typedef const uint8_t *__ptrauth_scan_results_action_record action_ptr_t;
+typedef const uint8_t* __ptrauth_scan_results_lsd lsd_ptr_t;
+typedef const uint8_t* __ptrauth_scan_results_action_record action_ptr_t;
 typedef uintptr_t __ptrauth_scan_results_landingpad_intptr landing_pad_t;
-typedef void *__ptrauth_scan_results_landingpad landing_pad_ptr_t;
+typedef void* __ptrauth_scan_results_landingpad landing_pad_ptr_t;
 
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
-    action_ptr_t   actionRecord; // Currently unused.  Retained to ease future maintenance.
-    lsd_ptr_t      languageSpecificData; // Needed only for __cxa_call_unexpected
-    landing_pad_t  landingPad;   // null -> nothing found, else something found
+    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future maintenance.
+    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t landingPad;       // null -> nothing found, else something found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -607,14 +607,10 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
   // We manually re-sign the IP as the __ptrauth qualifiers cannot
   // express the required relationship with the destination address
   const auto existingDiscriminator =
-      ptrauth_blend_discriminator(&results.landingPad,
-                                  __ptrauth_scan_results_landingpad_disc);
+      ptrauth_blend_discriminator(&results.landingPad, __ptrauth_scan_results_landingpad_disc);
   unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stackPointer, 0) */ =
-      (unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad,
-                                          __ptrauth_scan_results_landingpad_key,
-                                          existingDiscriminator,
-                                          ptrauth_key_return_address,
-                                          stackPointer);
+      (unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad, __ptrauth_scan_results_landingpad_key,
+                                          existingDiscriminator, ptrauth_key_return_address, stackPointer);
   _Unwind_SetIP(context, newIP);
 #else
   _Unwind_SetIP(context, results.landingPad);
@@ -971,51 +967,37 @@ _UA_CLEANUP_PHASE
 // trivial value union to coerce the types so instead we perform the re-signing
 // manually.
 using __cxa_catch_temp_type = decltype(__cxa_exception::catchTemp);
-static inline void set_landing_pad(scan_results& results,
-                                   const __cxa_catch_temp_type& source) {
-#if __has_feature(ptrauth_calls)
-  const uintptr_t sourceDiscriminator =
-      ptrauth_blend_discriminator(&source, __ptrauth_cxxabi_catch_temp_disc);
+static inline void set_landing_pad(scan_results& results, const __cxa_catch_temp_type& source) {
+#  if __has_feature(ptrauth_calls)
+  const uintptr_t sourceDiscriminator = ptrauth_blend_discriminator(&source, __ptrauth_cxxabi_catch_temp_disc);
   const uintptr_t targetDiscriminator =
-      ptrauth_blend_discriminator(&results.landingPad,
-                                  __ptrauth_scan_results_landingpad_disc);
-  uintptr_t reauthenticatedLandingPad =
-      (uintptr_t)ptrauth_auth_and_resign(*reinterpret_cast<void* const*>(&source),
-                                         __ptrauth_cxxabi_catch_temp_key,
-                                         sourceDiscriminator,
-                                         __ptrauth_scan_results_landingpad_key,
-                                         targetDiscriminator);
-  memmove(reinterpret_cast<void *>(&results.landingPad),
-          reinterpret_cast<void *>(&reauthenticatedLandingPad),
+      ptrauth_blend_discriminator(&results.landingPad, __ptrauth_scan_results_landingpad_disc);
+  uintptr_t reauthenticatedLandingPad = (uintptr_t)ptrauth_auth_and_resign(
+      *reinterpret_cast<void* const*>(&source), __ptrauth_cxxabi_catch_temp_key, sourceDiscriminator,
+      __ptrauth_scan_results_landingpad_key, targetDiscriminator);
+  memmove(reinterpret_cast<void*>(&results.landingPad), reinterpret_cast<void*>(&reauthenticatedLandingPad),
           sizeof(reauthenticatedLandingPad));
-#else
+#  else
   results.landingPad = reinterpret_cast<landing_pad_t>(source);
-#endif
+#  endif
 }
 
-static inline void get_landing_pad(__cxa_catch_temp_type &dest,
-                                   const scan_results &results) {
-#if __has_feature(ptrauth_calls)
+static inline void get_landing_pad(__cxa_catch_temp_type& dest, const scan_results& results) {
+#  if __has_feature(ptrauth_calls)
   const uintptr_t sourceDiscriminator =
-      ptrauth_blend_discriminator(&results.landingPad,
-                                  __ptrauth_scan_results_landingpad_disc);
-  const uintptr_t targetDiscriminator =
-      ptrauth_blend_discriminator(&dest, __ptrauth_cxxabi_catch_temp_disc);
-  uintptr_t reauthenticatedPointer =
-      (uintptr_t)ptrauth_auth_and_resign(*reinterpret_cast<void* const*>(&results.landingPad),
-                                         __ptrauth_scan_results_landingpad_key,
-                                         sourceDiscriminator,
-                                         __ptrauth_cxxabi_catch_temp_key,
-                                         targetDiscriminator);
-  memmove(reinterpret_cast<void *>(&dest),
-          reinterpret_cast<void *>(&reauthenticatedPointer),
+      ptrauth_blend_discriminator(&results.landingPad, __ptrauth_scan_results_landingpad_disc);
+  const uintptr_t targetDiscriminator = ptrauth_blend_discriminator(&dest, __ptrauth_cxxabi_catch_temp_disc);
+  uintptr_t reauthenticatedPointer = (uintptr_t)ptrauth_auth_and_resign(
+      *reinterpret_cast<void* const*>(&results.landingPad), __ptrauth_scan_results_landingpad_key, sourceDiscriminator,
+      __ptrauth_cxxabi_catch_temp_key, targetDiscriminator);
+  memmove(reinterpret_cast<void*>(&dest), reinterpret_cast<void*>(&reauthenticatedPointer),
           sizeof(reauthenticatedPointer));
-#else
+#  else
   dest = reinterpret_cast<__cxa_catch_temp_type>(results.landingPad);
-#endif
+#  endif
 }
 
-#ifdef __WASM_EXCEPTIONS__
+#  ifdef __WASM_EXCEPTIONS__
 _Unwind_Reason_Code __gxx_personality_wasm0
 #elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
 static _Unwind_Reason_Code __gxx_personality_imp
diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 343934e88..6595222f0 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -213,9 +213,9 @@
 #endif // _LIBUNWIND_IS_NATIVE_ONLY
 
 #if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
-#  define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
+#define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
 #elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
-#  error "Either both or none of ptrauth_calls and ptrauth_returns "\
+#error "Either both or none of ptrauth_calls and ptrauth_returns "\
          "is allowed to be enabled"
 #endif
 
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 18684ce31..1c7ec70c6 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -45,104 +45,119 @@
 
 #if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
 
-  #include <ptrauth.h>
-
-  // `__ptrauth_restricted_intptr` is a feature of apple clang that predates
-  // support for direct application of `__ptrauth` to integer types. This
-  // guard is necessary to support compilation with those compiler.
-  #if __has_extension(ptrauth_restricted_intptr_qualifier)
-    #define __unwind_ptrauth_restricted_intptr(...) \
-      __ptrauth_restricted_intptr(__VA_ARGS__)
-  #else
-    #define __unwind_ptrauth_restricted_intptr(...) \
-      __ptrauth(__VA_ARGS__)
-  #endif
-
-  // ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
-  #define __ptrauth_unwind_upi_handler_disc 0x7405
-
-  #define __ptrauth_unwind_upi_handler \
-    __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_upi_handler_disc)
-
-  #define __ptrauth_unwind_upi_handler_intptr \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,\
-                                       __ptrauth_unwind_upi_handler_disc)
-
-  // ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
-  #define __ptrauth_unwind_upi_startip \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xCA2C)
-
-  // ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
-  #define __ptrauth_unwind_upi_endip \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xE183)
-
-  // ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
-  #define __ptrauth_unwind_upi_lsda \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x83DE)
-
-  // ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
-  #define __ptrauth_unwind_upi_flags \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x79A1)
-
-  // ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
-  #define __ptrauth_unwind_upi_info \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xC20C)
-
-  // ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
-  #define __ptrauth_unwind_upi_extra \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x03DF)
-
-  // ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
-  #define __ptrauth_unwind_registers_arm64_link_reg \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1, 0x8301)
-
-  // ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
-  #define __ptrauth_unwind_uis_dso_base \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4FF5)
-
-  // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
-  #define __ptrauth_unwind_uis_dwarf_section \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4974)
-
-  // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A
-  #define __ptrauth_unwind_uis_dwarf_section_length \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x2A9A)
-
-  // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B
-  #define __ptrauth_unwind_uis_compact_unwind_section \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xA27B)
-
-  // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A
-  #define __ptrauth_unwind_uis_compact_unwind_section_length \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x5D0A)
-
-  // ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
-  #define __ptrauth_unwind_cie_info_personality_disc 0x6A40
-  #define __ptrauth_unwind_cie_info_personality \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \
-                                       __ptrauth_unwind_cie_info_personality_disc)
+#include <ptrauth.h>
+
+// `__ptrauth_restricted_intptr` is a feature of apple clang that predates
+// support for direct application of `__ptrauth` to integer types. This
+// guard is necessary to support compilation with those compiler.
+#if __has_extension(ptrauth_restricted_intptr_qualifier)
+#define __unwind_ptrauth_restricted_intptr(...)                                \
+  __ptrauth_restricted_intptr(__VA_ARGS__)
+#else
+#define __unwind_ptrauth_restricted_intptr(...) __ptrauth(__VA_ARGS__)
+#endif
 
-  // ptrauth_string_discriminator("personality") == 0x7EAD)
-  #define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD
+// ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
+#define __ptrauth_unwind_upi_handler_disc 0x7405
+
+#define __ptrauth_unwind_upi_handler                                           \
+  __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_upi_handler_disc)
+
+#define __ptrauth_unwind_upi_handler_intptr                                    \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,          \
+                                     __ptrauth_unwind_upi_handler_disc)
+
+// ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
+#define __ptrauth_unwind_upi_startip                                           \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1,  \
+                                     0xCA2C)
+
+// ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
+#define __ptrauth_unwind_upi_endip                                             \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1,  \
+                                     0xE183)
+
+// ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
+#define __ptrauth_unwind_upi_lsda                                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x83DE)
+
+// ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
+#define __ptrauth_unwind_upi_flags                                             \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x79A1)
+
+// ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
+#define __ptrauth_unwind_upi_info                                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0xC20C)
+
+// ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
+#define __ptrauth_unwind_upi_extra                                             \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x03DF)
+
+// ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
+#define __ptrauth_unwind_registers_arm64_link_reg                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1,    \
+                                     0x8301)
+
+// ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
+#define __ptrauth_unwind_uis_dso_base                                          \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x4FF5)
+
+// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
+#define __ptrauth_unwind_uis_dwarf_section                                     \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x4974)
+
+// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") ==
+// 0x2A9A
+#define __ptrauth_unwind_uis_dwarf_section_length                              \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x2A9A)
+
+// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") ==
+// 0xA27B
+#define __ptrauth_unwind_uis_compact_unwind_section                            \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0xA27B)
+
+// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length")
+// == 0x5D0A
+#define __ptrauth_unwind_uis_compact_unwind_section_length                     \
+  __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1,    \
+                                     0x5D0A)
+
+// ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
+#define __ptrauth_unwind_cie_info_personality_disc 0x6A40
+#define __ptrauth_unwind_cie_info_personality                                  \
+  __unwind_ptrauth_restricted_intptr(                                          \
+      ptrauth_key_function_pointer, 1,                                         \
+      __ptrauth_unwind_cie_info_personality_disc)
+
+// ptrauth_string_discriminator("personality") == 0x7EAD)
+#define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD
 
 #else
 
-  #define __unwind_ptrauth_restricted_intptr(...)
-  #define __ptrauth_unwind_upi_handler
-  #define __ptrauth_unwind_upi_handler_intptr
-  #define __ptrauth_unwind_upi_startip
-  #define __ptrauth_unwind_upi_endip
-  #define __ptrauth_unwind_upi_lsda
-  #define __ptrauth_unwind_upi_flags
-  #define __ptrauth_unwind_upi_info
-  #define __ptrauth_unwind_upi_extra
-  #define __ptrauth_unwind_registers_arm64_link_reg
-  #define __ptrauth_unwind_uis_dso_base
-  #define __ptrauth_unwind_uis_dwarf_section
-  #define __ptrauth_unwind_uis_dwarf_section_length
-  #define __ptrauth_unwind_uis_compact_unwind_section
-  #define __ptrauth_unwind_uis_compact_unwind_section_length
-  #define __ptrauth_unwind_cie_info_personality
+#define __unwind_ptrauth_restricted_intptr(...)
+#define __ptrauth_unwind_upi_handler
+#define __ptrauth_unwind_upi_handler_intptr
+#define __ptrauth_unwind_upi_startip
+#define __ptrauth_unwind_upi_endip
+#define __ptrauth_unwind_upi_lsda
+#define __ptrauth_unwind_upi_flags
+#define __ptrauth_unwind_upi_info
+#define __ptrauth_unwind_upi_extra
+#define __ptrauth_unwind_registers_arm64_link_reg
+#define __ptrauth_unwind_uis_dso_base
+#define __ptrauth_unwind_uis_dwarf_section
+#define __ptrauth_unwind_uis_dwarf_section_length
+#define __ptrauth_unwind_uis_compact_unwind_section
+#define __ptrauth_unwind_uis_compact_unwind_section_length
+#define __ptrauth_unwind_cie_info_personality
 
 #endif
 
@@ -191,18 +206,23 @@ typedef double unw_fpreg_t;
 #endif
 
 struct unw_proc_info_t {
-  unw_word_t __ptrauth_unwind_upi_startip start_ip; /* start address of function */
-  unw_word_t __ptrauth_unwind_upi_endip end_ip;     /* address after end of function */
-  unw_word_t __ptrauth_unwind_upi_lsda lsda;        /* address of language specific data area, */
-                                                    /* or zero if not used */
+  unw_word_t __ptrauth_unwind_upi_startip
+      start_ip; /* start address of function */
+  unw_word_t __ptrauth_unwind_upi_endip
+      end_ip; /* address after end of function */
+  unw_word_t __ptrauth_unwind_upi_lsda
+      lsda; /* address of language specific data area, */
+            /* or zero if not used */
 
   unw_word_t __ptrauth_unwind_upi_handler_intptr handler;
-  unw_word_t  gp;                                   /* not used */
-  unw_word_t __ptrauth_unwind_upi_flags flags;      /* not used */
-  uint32_t   format;                                /* compact unwind encoding, or zero if none */
-  uint32_t   unwind_info_size;                      /* size of DWARF unwind info, or zero if none */
-  unw_word_t __ptrauth_unwind_upi_info unwind_info; /* address of DWARF unwind info, or zero */
-  unw_word_t __ptrauth_unwind_upi_extra extra;      /* mach_header of mach-o image containing func */
+  unw_word_t gp;                               /* not used */
+  unw_word_t __ptrauth_unwind_upi_flags flags; /* not used */
+  uint32_t format;           /* compact unwind encoding, or zero if none */
+  uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
+  unw_word_t __ptrauth_unwind_upi_info
+      unwind_info; /* address of DWARF unwind info, or zero */
+  unw_word_t __ptrauth_unwind_upi_extra
+      extra; /* mach_header of mach-o image containing func */
 };
 typedef struct unw_proc_info_t unw_proc_info_t;
 
diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
index 63f9cb367..f38dda47c 100644
--- a/libunwind/src/AddressSpace.hpp
+++ b/libunwind/src/AddressSpace.hpp
@@ -129,27 +129,24 @@ struct UnwindInfoSections {
     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) ||                              \
     defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
   // No dso_base for SEH.
-  uintptr_t __ptrauth_unwind_uis_dso_base
-                  dso_base = 0;
+  uintptr_t __ptrauth_unwind_uis_dso_base dso_base = 0;
 #endif
 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
   size_t          text_segment_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-  uintptr_t __ptrauth_unwind_uis_dwarf_section
-                  dwarf_section = 0;
-  size_t __ptrauth_unwind_uis_dwarf_section_length
-                  dwarf_section_length = 0;
+  uintptr_t __ptrauth_unwind_uis_dwarf_section dwarf_section = 0;
+  size_t __ptrauth_unwind_uis_dwarf_section_length dwarf_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
   uintptr_t       dwarf_index_section;
   size_t          dwarf_index_section_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-  uintptr_t __ptrauth_unwind_uis_compact_unwind_section
-                  compact_unwind_section = 0;
+  uintptr_t __ptrauth_unwind_uis_compact_unwind_section compact_unwind_section =
+      0;
   size_t __ptrauth_unwind_uis_compact_unwind_section_length
-                  compact_unwind_section_length = 0;
+      compact_unwind_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_ARM_EHABI)
   uintptr_t       arm_section;
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index d9fa76c57..d2822e8be 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -302,7 +302,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
 
       isSignalFrame = cieInfo.isSignalFrame;
 
-#if defined(_LIBUNWIND_TARGET_AARCH64) && \
+#if defined(_LIBUNWIND_TARGET_AARCH64) &&                                      \
     !defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
       // There are two ways of return address signing: pac-ret (enabled via
       // -mbranch-protection=pac-ret) and ptrauth-returns (enabled as part of
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index e7dc889da..81e98597e 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1863,29 +1863,25 @@ public:
 
   uint64_t  getSP() const         { return _registers.__sp; }
   void      setSP(uint64_t value) { _registers.__sp = value; }
-  uint64_t  getIP() const {
+  uint64_t getIP() const {
     uint64_t value = _registers.__pc;
 #if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
     // Note the value of the PC was signed to its address in the register state
     // but everyone else expects it to be sign by the SP, so convert on return.
-    value = (uint64_t)ptrauth_auth_and_resign((void *)_registers.__pc,
-                                              ptrauth_key_return_address,
-                                              &_registers.__pc,
-                                              ptrauth_key_return_address,
-                                              getSP());
+    value = (uint64_t)ptrauth_auth_and_resign(
+        (void *)_registers.__pc, ptrauth_key_return_address, &_registers.__pc,
+        ptrauth_key_return_address, getSP());
 #endif
     return value;
   }
-  void      setIP(uint64_t value) {
+  void setIP(uint64_t value) {
 #if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
     // Note the value which was set should have been signed with the SP.
     // We then resign with the slot we are being stored in to so that both SP
     // and LR can't be spoofed at the same time.
-    value = (uint64_t)ptrauth_auth_and_resign((void *)value,
-                                              ptrauth_key_return_address,
-                                              getSP(),
-                                              ptrauth_key_return_address,
-                                              &_registers.__pc);
+    value = (uint64_t)ptrauth_auth_and_resign(
+        (void *)value, ptrauth_key_return_address, getSP(),
+        ptrauth_key_return_address, &_registers.__pc);
 #endif
     _registers.__pc = value;
   }
@@ -1898,10 +1894,9 @@ public:
                                   link_reg_t *referenceAuthedLinkRegister) {
     // If we are in an arm64/arm64e frame, then the PC should have been signed
     // with the SP
-    *referenceAuthedLinkRegister =
-      (uint64_t)ptrauth_auth_data((void *)inplaceAuthedLinkRegister,
-                                  ptrauth_key_return_address,
-                                  _registers.__sp);
+    *referenceAuthedLinkRegister = (uint64_t)ptrauth_auth_data(
+        (void *)inplaceAuthedLinkRegister, ptrauth_key_return_address,
+        _registers.__sp);
   }
 #endif
 
@@ -1951,7 +1946,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   // performed by setIP.
   uint64_t pcRegister = 0;
   memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
-         sizeof(pcRegister));
+          sizeof(pcRegister));
   setIP(pcRegister);
 #endif
 }
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 689398245..7ec5f9e91 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -2010,8 +2010,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
   // re-signed the pointer, and assigning directly will attempt to incorrectly
   // sign the already signed value.
   memmove(reinterpret_cast<void *>(&_info.handler),
-          reinterpret_cast<void *>(&personality),
-          sizeof(personality));
+          reinterpret_cast<void *>(&personality), sizeof(personality));
   _info.gp = 0;
   _info.flags = 0;
   _info.format = encoding;
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index 994b116f6..2cca0e438 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -97,13 +97,13 @@
 // is possible as `_Unwind_Personality_Fn` is a standard function pointer, and
 // as such is not address diversified.
 static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
-  uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer,
-                                               0,
-                                               ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
-    reauthenticatedIntegerHandler = frameInfo->handler;
+  uintptr_t __unwind_ptrauth_restricted_intptr(
+      ptrauth_key_function_pointer, 0,
+      ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
+      reauthenticatedIntegerHandler = frameInfo->handler;
   _Unwind_Personality_Fn handler;
   memmove(&handler, (void *)&reauthenticatedIntegerHandler,
-         sizeof(_Unwind_Personality_Fn));
+          sizeof(_Unwind_Personality_Fn));
   return handler;
 }
 

@ojhunt ojhunt force-pushed the users/ojhunt/pointer-authenticated-unwinding branch 2 times, most recently from 6810396 to 637245f Compare June 7, 2025 02:22
@asl
Copy link
Collaborator

asl commented Jun 7, 2025

@kovdan01 @atrosinenko Please take a look

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 7, 2025

Updating formatting before review - had discussed with Louis and he expressed a preference for some of it, but this llvm.org style bot complains many other cases (likely a local config issue when I was trying to cleanup the downstream code.

So I've updated with a direct clang-format fix.

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 8, 2025

unused variable errors are likely fallout from refactoring and workaround removals I did as part of the prep, will do some cleanup/diagnostics work later this week.

I mostly wanted to get this available to others to see whether they were ok adopting this rather than rolling their own version.

@kovdan01
Copy link
Contributor

@ojhunt JFYI: I've published a couple of small fixes I've applied locally at https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-fix0/. Maybe this would be useful

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 18, 2025

@ojhunt JFYI: I've published a couple of small fixes I've applied locally at https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-fix0/. Maybe this would be useful

I'd posted this to try and avoid too much duplicated work so it's highly possible some of these issues are due to me screwing up refactoring, cleanups, or the patch preparation. I'll get back to this after wg21 wraps up this week, so sorry for the delays.

@ojhunt
Copy link
Contributor Author

ojhunt commented Jun 25, 2025

I'll be back to working on this later today - there's a pile of feedback, and a bunch of nonsense that I managed to accidentally accrue and/or re-format when pushing the PR so it will take a little time to unbreak that. It may be easiest to force push a repaired PR first and then address comments.

I also realize that some of the breakage might be due to mismatched APPLE vs has_feature(actual_feature)

Copy link
Contributor

@atrosinenko atrosinenko left a comment

Choose a reason for hiding this comment

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

I have tested this patch on Linux with aarch64-linux-pauthtest triple and custom-built sysroot, here are the results.

In my setup, the tests pass on the following modified branch: https://github.com/atrosinenko/llvm-project/commits/pointer-authenticated-unwinding-fix1/. It is based on https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-fix0/ with the following changes:

  • Currently, several parts of the patch are only enabled on Apple targets. For testing purposes, I unconditionally enabled parts of this patch guarded by defined(__APPLE__).
  • It turned out that __has_feature(ptrauth_qualifier) does not work in mainline, so I replaced it with __has_feature(ptrauth_intrinsics). I expect the correct solution proposed by @kovdan01 (replacing with __has_extension(ptrauth_qualifier)) to behave identically.
  • The change to compiler-rt/lib/profile/InstrProfilingValue.c seems to be unrelated to libunwind
  • The most meaningful change is updating signing schemas is several places - see inline comments. Additionally, I had to update a few other places that I cannot add inline comments to
    • in Registers_arm64::getRegister and Registers_arm64::setRegister, replace direct references to _registers.__pc with calls to getIP() and setIP(), correspondingly
    • disable the existing pauth-related logic in DwarfInstructions<A, R>::stepWithDwarf

The fact I'm worried about is whether implicit signing and authentication on accesses to __ptrauth-qualified fields may introduce signing or authentication oracles usable by an attacker, since many values stored to these fields are initially non-signed. This is possibly mitigated by the fact that all these fields use address diversity with distinct integer discriminators and/or the original values are taken from read-only memory. On the other hand, discriminator computation, auth / sign intrinsic and load / store to memory are currently three separate operations when accessing a __ptrauth-qualified field, thus spilling of intermediate values to the stack is possible. Furthermore, even if the non-signed value originates from a read-only memory, this is not expressed in LLVM IR terms, thus the optimization pipeline may transform sensitive instruction sequences in an unsafe way.

@ojhunt ojhunt force-pushed the users/ojhunt/pointer-authenticated-unwinding branch from 5f5f75e to ad625da Compare September 27, 2025 23:50
@ojhunt
Copy link
Contributor Author

ojhunt commented Sep 27, 2025

Had to rebase as there was a divergence between my tree and this one - possibly I accidentally merged main to the PR

@ojhunt
Copy link
Contributor Author

ojhunt commented Sep 28, 2025

@ojhunt I closed all the threads which are no longer relevant or are duplicates.

👍

To be done in scope of this PR

Trivial formatting issues

These require almost zero effort to apply. Please consider fixing these first so we do not need to worry about them anymore.

Done

Non-trivial styling-related issues

  1. Refactor preprocessor checks against ptrauth. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369029642 and commit 644405b
  2. Avoid use of __ptrauth_restricted_intptr which is not present in mainline. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369036612 and commit a2390e1. I do get the point that it's needed in downstream, but I suppose that it's better to avoid exposing downstream-specific stuff to mainline. I suppose that you can use a simple downstream patch over mainline libunwind which would resolve the build issue for you.

That would mean that apple clang will not be able to build the runtimes. That's not a real option.

  1. Do smth with [[maybe_unused]] attribute which only serves as a workaround for a spurious compiler bug. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2368805350 and commit 4eaa8c7

I've moved this behind a matching #define of the code that calls them, I'm trying to work out if there is a real reason for the functions being separated from their usage as much as they are.

An issue causing a runtime crash

Do not mix pac-ret and ptrauth_returns. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369419226 and commit ced8b99.

Fixed with an arm64e guard.

Other non-trivial issues

Verify FP is handled correctly https://github.com/llvm/llvm-project/pull/143230/files#r2369428305

It is, I've fixed the misleading - we were experimenting with signed frame pointers for a while.

To be done as a follow-up

  1. [PAC] Update pointer authentication docs #96528 (comment)
  2. [PAC][libunwind] Refactor way of describing internal signing schemas #160101
  3. [PAC][libunwind] Unify signed return address handling logic #160110
  4. [PAC][libunwind] Investigate if compatibility with v8.2-a could be enhanced #160114

Pinged Ahmed on this one, I don't know the full impact of that change

  1. [PAC][libunwind] Enhance comments and error messages related to libunwind hardening #160117

My preference would be to remove those from release builds entirely and replace LIBUNWIND_ABORT() with explicit immediate traps.

  1. [PAC][libunwind] Move signing schemas which are part of public ABI to ptrauth.h header #160119

This is possibly difficult. The functional ABI implication of most of these is purely between libcxx and libcxxabi, and our platform model does not support updating/changing those separately, which means we think we might be able to change/improve some of the aspects in future. Moving them to ptrauth.h functionally removes that option even if there was no technical reason to.

  1. [PAC][ibunwind] Support signed personality pointer on Linux targets #160120

this is the "personality" discriminated one right? I think I already incorporated it into the latest revision.

@ojhunt
Copy link
Contributor Author

ojhunt commented Sep 28, 2025

Sigh, built wrong repo, basic errors which I'm fixing now

T signed_personality) {
static_assert(sizeof(info->personality) == sizeof(signed_personality),
"Signed personality is the wrong size");
memmove((void *)&info->personality, (void *)&signed_personality,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I guess we can just use memcpy since memmove has additional overhead of handling overlapping memory regions. Here, signed_personality is a local variable, so we can guarantee that there is no overlapping.

Also, it's probably worth explicitly including <string.h> (well, <cstring> should be better for C++ headers, but we already have includes for C-style headers, so let's stick with existing conventions)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmmm, other platforms haven't simply adopted the "handle overlap correctly everywhere" approach? :-/

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmmm, other platforms haven't simply adopted the "handle overlap correctly everywhere" approach? :-/

@ojhunt I honestly can't say for all the platforms, but I suppose that memcpy expresses the intention better than memmove here

@kovdan01
Copy link
Contributor

@ojhunt Thanks for an update! I've resolved several threads, but some things should still be fixed.

Please let me know if you have any comments/questions or any help is needed from my side.

Trivial style-related issues

These require almost zero effort to apply. Please consider fixing these first so we do not need to worry about them anymore.

  1. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  2. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  3. [runtimes][PAC] Harden unwinding when possible #143230 (comment)

Non-trivial styling-related issues

Refactor preprocessor checks against ptrauth. See thread #143230 (comment) and proposed fix 644405b

Breaking change to be reverted

An issue causing a runtime crash

Do not mix pac-ret and ptrauth_returns. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369419226 and commit ced8b99.

Fixed with an arm64e guard.

This does not seem to fix the originally described issue, moreover, it looks like this breaks previously working behavior. See #143230 (comment).

@ojhunt
Copy link
Contributor Author

ojhunt commented Oct 2, 2025

@ojhunt Thanks for an update! I've resolved several threads, but some things should still be fixed.

Please let me know if you have any comments/questions or any help is needed from my side.

Trivial style-related issues

These require almost zero effort to apply. Please consider fixing these first so we do not need to worry about them anymore.

  1. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  2. [runtimes][PAC] Harden unwinding when possible #143230 (comment)
  3. [runtimes][PAC] Harden unwinding when possible #143230 (comment)

I think fixed?

Non-trivial styling-related issues

Refactor preprocessor checks against ptrauth. See thread #143230 (comment) and proposed fix 644405b

That sounds ok

Breaking change to be reverted

An issue causing a runtime crash

Do not mix pac-ret and ptrauth_returns. See thread https://github.com/llvm/llvm-project/pull/143230/files#r2369419226 and commit ced8b99.

Fixed with an arm64e guard.

This does not seem to fix the originally described issue, moreover, it looks like this breaks previously working behavior. See #143230 (comment).

Minor detail :D

I think fixed correctly now (based on what you posted) but I need to verify the correct thing happens on arm64e (this will take a few days).

There's still the ifdef'd definition of the helper function in the current version, but I'll move that around in a bit.

@ojhunt ojhunt requested a review from ldionne October 3, 2025 22:27
__ptrauth_unwind_cie_info_personality_disc)

// ptrauth_string_discriminator("personality") == 0x7EAD)
#define __ptrauth_unwind_pacret_personality_disc 0x7EAD
Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose the name is a bit misleading. Let's use smth like the following:

Suggested change
#define __ptrauth_unwind_pacret_personality_disc 0x7EAD
#define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD

// __ptrauth_nop_cast cannot be used here as the authentication schemas include
// address diversification.
template <typename PtrType>
void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'll open a "placeholder" thread just as a reminder that we need to get #161027 with additional macros merged first, and make use of those macros instead of these functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

none of those macros work -> these are address discriminated values. That's also why memcpy does not work.

_Unwind_Personality_Fn __ptrauth_unwind_upi_handler *handler;
} u;
u.opaque_handler = (void *)&frameInfo->handler;
return *u.handler;
Copy link
Contributor

Choose a reason for hiding this comment

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

While this should be valid in C, in C++ reading from the member of the union that wasn't most recently written is technically UB: https://en.cppreference.com/w/cpp/language/union.html.

I think we need to conform to C++ standard and use smth like memcpy for doing such a trick.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

memcpy cannot be used -> these are address discriminated values, the entire reason for these hoops is to deal with this problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The alternative is to force a copy + re-sign

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I think the issues that these workarounds were actually needed for have since been resolved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was wrong, the problems still exist. I should really add a warning. I had forgotten the problem, so I thought it was doing the right thing when I briefly looked at the code. It is not, essentially the issues are variations on:

uintptr_t __ptrauth(....) i;
some_func_ptr_t f;
f = (some_func_ptr_t)i;

reading i authenticates it, then the cast to some_func_ptr_t assumes it's the standard int->function pointer cast (which assumes the source integer is an opaque function pointer with a valid signature), and does not re-sign.


#include <ptrauth.h>

#if __has_extension(ptrauth_restricted_intptr_qualifier)
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's add a comment explaining that we need that because of Apple's fork so people unaware of the problem would know why such checks are needed.

The comment might look like this:

// In Apple's fork of clang, `__ptrauth` qualifier can be only applied to
// pointer types, and `__ptrauth_restricted_intptr` is used instead for
// integer types. In mainline clang, we only have `__ptrauth` which could
// be applied both to pointer and integer types.
// These helper macros allow seemless build of runtime libraries with
// Apple's fork of clang.
// TODO: If/when Apple's clang switches to mainline way of using
// `__ptrauth` qualifier, get rid of these conditionals.

unw_word_t result;
__unw_get_reg(cursor, UNW_REG_IP, &result);

#if defined(__ARM64E__)
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like you've accidentally changes this from a generic check against ptrauth being enabled to a check against arm64e. To make tests passing on Linux, we need to use smth like _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Righto, I thought this was one of the arm64e specific behaviors

@kovdan01
Copy link
Contributor

kovdan01 commented Oct 6, 2025

@ojhunt Thanks for an update! With the latest fixes, we only have one trivial issue which prevents Linux tests from passing (and I believe that it was introduced accidentally and it looks like that we need literally zero effort to fix that). With that being fixed, tests are passing on Linux in the following configurations:

  1. Pauthtest for both runtime libraries and executables
  2. Pac-ret for both runtime libraries and executables
  3. Pac-ret for executables but not runtime libraries
  4. No pauth at all (on aarch64)

Besides that, there are several other small issues here and there. See the list below.

Please let me know if any help with fixing these issues is needed - I would be glad to provide any support.

  1. Use a check against _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING against a check against arm64e: [runtimes][PAC] Harden unwinding when possible #143230 (comment)
    This is the only thing which prevents linux tests from passing.

  2. Avoid UB in get_handler_function: [runtimes][PAC] Harden unwinding when possible #143230 (comment)
    Similar issue should also be addressed in [clang][PAC][NFC] Provide addition support macros to ptrauth.h #161027 (comment)

(The issues below could be resolved in follow-up PRs, keeping description here not to lose them)

  1. It looks like that while _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING macro was added (and it's used in some places), in most cases we still have plain checks against __has_feature(ptrauth_calls) and __has_feature(ptrauth_returns). As discussed earlier, it's better to use this macro for such checks. See thread [runtimes][PAC] Harden unwinding when possible #143230 (comment) and proposed fix 644405b

  2. Add a comment explaining conditionals regarding __ptrauth_restricted_intptr qualifier to make it clearer for thouse not familiar with Apple's clang specific. I've provided an example comments, see [runtimes][PAC] Harden unwinding when possible #143230 (comment)

  3. __ptrauth_unwind_pacret_personality_disc should probably be renamed to __ptrauth_unwind_pauthtest_personality_disc. It's clearly not related to pac-ret which is about LR signing only. See [runtimes][PAC] Harden unwinding when possible #143230 (comment)

Looking forward for further updates and hope that this could be finally merged relatively soon :)

ojhunt added 4 commits October 7, 2025 15:55
* Add note for `__ptrauth_restricted_intptr`
* Rename confusing parameter in set_landing_pad_as_ptr
* Rename __ptrauth_unwind_pacret_personality_disc to
  __ptrauth_unwind_pauthtest_personality_disc
Stop using unions to deal with the pointer auth cast semantics,
instead perform manual re-signing. This means the templated helper
functions no longer need to be templates and so don't need to be
in a separated non-extern "C" block.

Fixing up the comments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler-rt:builtins compiler-rt hardening Issues related to the hardening effort libc++abi libc++abi C++ Runtime Library. Not libc++. libunwind PGO Profile Guided Optimizations
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

6 participants