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 ahmedbougacha, asl 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 hpp,cpp,c,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 --diff_from_common_commit

⚠️
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/Registers.hpp b/libunwind/src/Registers.hpp
index 5a5b57835..fc8f03637 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
 
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index b0cd60dfb..2cca0e438 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -97,10 +97,10 @@
 // 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));
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 951d87db8..034129ada 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -136,9 +136,8 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
         // For this to be generally usable we manually re-sign it to the
         // directly supported schema:
         //   __ptrauth(ptrauth_key_return_address, 1, 0)
-        unw_word_t
-              __unwind_ptrauth_restricted_intptr(ptrauth_key_return_address, 1,
-                                                 0) authenticated_value;
+        unw_word_t __unwind_ptrauth_restricted_intptr(
+            ptrauth_key_return_address, 1, 0) authenticated_value;
         unw_word_t opaque_value = (uint64_t)ptrauth_auth_and_resign(
             (void *)value, ptrauth_key_return_address, sp,
             ptrauth_key_return_address, &authenticated_value);

@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.

* 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.
@ojhunt ojhunt force-pushed the users/ojhunt/pointer-authenticated-unwinding branch from e059e1c to 0f2679a Compare October 15, 2025 04:00
@ojhunt ojhunt requested a review from kovdan01 October 15, 2025 04:01
@ojhunt
Copy link
Contributor Author

ojhunt commented Oct 15, 2025

Remaining formatting changes differ significantly from the surrounding code. I don't want to intermingle significant changes with formatting changes.

@ojhunt
Copy link
Contributor Author

ojhunt commented Oct 17, 2025

gnahhhhhh why is a9d9113 apparently fixing the armv8 build? That implies something it assuming Arm64Registers is a POD type, and I can't work out where :-/

Copy link
Contributor

@kovdan01 kovdan01 left a comment

Choose a reason for hiding this comment

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

@ojhunt Thanks for tons of fixes! We have one more usage of unions in libunwind.cpp which is technically UB.

I've proposed a fix for this. See commit a29af82 from my branch ptrauth-unwinding-2025-10-19

As soon as this is addressed, I have no other objections from my side regarding this PR. Thanks for a great work!

#include "dwarf2.h"
#include "libunwind_ext.h"


Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: unintended formatting change

// This is important for ptrauth, otherwise the IP cannot be correctly
// signed.
// We re-sign to a more usable form and then use it directly.
union {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please avoid using unions here as well since reading from authenticated_value while opaque_value was the last assigned member is UB in C++.

I've prepared a fix which works on my side. You are welcome to just apply that if you are happy with the fix implementation. See commit a29af82 from my branch ptrauth-unwinding-2025-10-19

Copy link
Contributor

@kovdan01 kovdan01 left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@ojhunt ojhunt merged commit e6a1aff into main Oct 20, 2025
76 of 77 checks passed
@ojhunt ojhunt deleted the users/ojhunt/pointer-authenticated-unwinding branch October 20, 2025 16:57
@github-project-automation github-project-automation bot moved this from In Progress to Done in Pointer Authentication Tasks Oct 20, 2025
@dyung
Copy link
Collaborator

dyung commented Oct 22, 2025

@ojhunt, just in case it gets lost in the comments, the usage of #if __has_feature(ptrauth_calls) seems to break compiling with GCC 13.3:

https://godbolt.org/z/WW95ad5rP

Can you fix or revert so that we can get this building again with GCC?

@ojhunt
Copy link
Contributor Author

ojhunt commented Oct 22, 2025

Will fix momentarily. I guess gcc does not have __has_feature, so I'll look at how libunwind usually does this. We may just gate on the AARCH_PTRAUTH flag instead.

@asl
Copy link
Collaborator

asl commented Oct 22, 2025

Will fix momentarily. I guess gcc does not have __has_feature, so I'll look at how libunwind usually does this. We may just gate on the AARCH_PTRAUTH flag instead.

libunwind.cpp contains the following:

// Define the __has_feature extension for compilers that do not support it so
// that we can later check for the presence of ASan in a compiler-neutral way.
#if !defined(__has_feature)
#define __has_feature(feature) 0
#endif

So I'd guess we need to move this into some common (but private) header and reuse for UnwindRegistersRestore.S and UnwindRegistersSave.S. Maybe to config.h?

@ojhunt
Copy link
Contributor Author

ojhunt commented Oct 22, 2025

I think polluting space with __has_feature is the wrong approach, will gate on __PTRAUTH__ || __arm64e__ if you can verify that __PTRAUTH__ is defined for you folk when building the .S files

@ojhunt
Copy link
Contributor Author

ojhunt commented Oct 22, 2025

PR up at #164535

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: Done

Development

Successfully merging this pull request may close these issues.

7 participants