From ebdbb51474c6085423a85ee167410b326c44dafa Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:12:59 -0400 Subject: [PATCH 01/13] Update deployment targets to macOS 14 minimum --- CrashReporter.xcodeproj/project.pbxproj | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/CrashReporter.xcodeproj/project.pbxproj b/CrashReporter.xcodeproj/project.pbxproj index 3f5c4587..e88f9392 100644 --- a/CrashReporter.xcodeproj/project.pbxproj +++ b/CrashReporter.xcodeproj/project.pbxproj @@ -2808,7 +2808,6 @@ 05E7485C1760D62A009B8745 /* PLCrashAsyncDwarfFDE.hpp in Headers */, 05E7488C176135CF009B8745 /* PLCrashAsyncDwarfExpression.hpp in Headers */, 05E748B017616D30009B8745 /* dwarf_stack.hpp in Headers */, - 1F14AC842BACB4330037FCD3 /* CPPCrashHelper.h in Headers */, 05C76DAF176B8C7000E9B10D /* dwarf_opstream.hpp in Headers */, 05C76DD1176FBAF300E9B10D /* PLCrashAsyncDwarfCFAState.hpp in Headers */, 05920D27177B9257001E8975 /* PLCrashFrameDWARFUnwind.h in Headers */, @@ -2943,7 +2942,6 @@ 8064D7CB1C4D22D8005A8B4C /* PLCrashAsyncDwarfFDE.hpp in Headers */, 8064D7CC1C4D22D8005A8B4C /* PLCrashAsyncDwarfExpression.hpp in Headers */, 8064D7CD1C4D22D8005A8B4C /* dwarf_stack.hpp in Headers */, - 1F14AC862BACB4330037FCD3 /* CPPCrashHelper.h in Headers */, 8064D7CE1C4D22D8005A8B4C /* dwarf_opstream.hpp in Headers */, 8064D7CF1C4D22D8005A8B4C /* PLCrashAsyncDwarfCFAState.hpp in Headers */, 8064D7D01C4D22D8005A8B4C /* PLCrashFrameDWARFUnwind.h in Headers */, @@ -3906,7 +3904,6 @@ 05BEC42817BD4F290082CBFB /* PLCrashAsyncMachExceptionInfo.c in Sources */, 05BEC43C17BF1CB10082CBFB /* PLCrashReporterConfig.m in Sources */, 05A5E28A17C04188008A75E5 /* PLCrashAsyncLinkedList.cpp in Sources */, - 1F14AC832BACB4330037FCD3 /* CPPCrashHelper.mm in Sources */, 05B929EE17C9336600B051E3 /* PLCrashUncaughtExceptionHandler.m in Sources */, 0513E23A17D15ED400727919 /* PLCrashReportMachExceptionInfo.m in Sources */, ); @@ -4402,7 +4399,6 @@ 8064D7FD1C4D22D8005A8B4C /* PLCrashMachExceptionServer.m in Sources */, 8064D7FE1C4D22D8005A8B4C /* PLCrashFrameStackUnwind.c in Sources */, 8064D7FF1C4D22D8005A8B4C /* PLCrashAsyncThread.c in Sources */, - 1F14AC852BACB4330037FCD3 /* CPPCrashHelper.mm in Sources */, 8064D8001C4D22D8005A8B4C /* PLCrashAsyncThread_x86.c in Sources */, C2C80E102350D23B0084D513 /* protobuf-c.c in Sources */, 8064D8011C4D22D8005A8B4C /* PLCrashAsyncThread_arm.c in Sources */, @@ -5726,7 +5722,7 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_SHADOW = YES; HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/protobuf-c\""; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 14.0; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", @@ -5778,7 +5774,7 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_SHADOW = YES; HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Dependencies/protobuf-c\""; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 14.0; OTHER_CFLAGS = ( "$(inherited)", "-D$(PL_BUILD_CONFIG_FLAG)=1", @@ -5882,7 +5878,6 @@ GCC_ENABLE_EXCEPTIONS = NO; GCC_OPTIMIZATION_LEVEL = 0; MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = 10.11; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", @@ -5908,7 +5903,6 @@ EXPORTED_SYMBOLS_FILE = Resources/CrashReporter.exp; GCC_ENABLE_EXCEPTIONS = NO; MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = 10.11; ONLY_ACTIVE_ARCH = NO; OTHER_CFLAGS = ( "$(inherited)", From 768dccba1ae035ef86f92b12638c1f5c8c549a34 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:13:26 -0400 Subject: [PATCH 02/13] Fix deprecation issue with OSSpinLock > PLCrashAsyncLinkedList.hpp:155:5: 'OSSpinLock' is deprecated: first deprecated in macOS 10.12 - Use os_unfair_lock() from instead --- Source/PLCrashAsyncLinkedList.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Source/PLCrashAsyncLinkedList.hpp b/Source/PLCrashAsyncLinkedList.hpp index 83ad078a..e7c37ba6 100644 --- a/Source/PLCrashAsyncLinkedList.hpp +++ b/Source/PLCrashAsyncLinkedList.hpp @@ -32,6 +32,7 @@ #include "PLCrashAsync.h" #include "PLCrashMacros.h" #include +#include PLCR_CPP_BEGIN_NS namespace async { @@ -152,7 +153,7 @@ class async_list { void free_list (node *next); /** The lock used by writers. No lock is required for readers. */ - OSSpinLock _write_lock; + os_unfair_lock _write_lock; /** The head of the list, or NULL if the list is empty. Must only be used to iterate or delete entries. */ node *_head; @@ -174,7 +175,7 @@ template async_list::async_list (void) { _tail = NULL; _free = NULL; _refcount = 0; - _write_lock = OS_SPINLOCK_INIT; + _write_lock = OS_UNFAIR_LOCK_INIT; } template async_list::~async_list (void) { @@ -195,7 +196,7 @@ template async_list::~async_list (void) { */ template void async_list::nasync_prepend (V value) { /* Lock the list from other writers. */ - OSSpinLockLock(&_write_lock); { + os_unfair_lock_lock(&_write_lock); { /* Construct the new entry, or recycle an existing one. */ node *new_node; if (_free != NULL) { @@ -242,7 +243,7 @@ template void async_list::nasync_prepend (V value) { PLCF_DEBUG("Failed to prepend to image list despite holding lock"); } } - } OSSpinLockUnlock(&_write_lock); + } os_unfair_lock_unlock(&_write_lock); } @@ -256,7 +257,7 @@ template void async_list::nasync_prepend (V value) { template void async_list::nasync_append (V value) { /* Lock the list from other writers. */ - OSSpinLockLock(&_write_lock); { + os_unfair_lock_lock(&_write_lock); { /* Construct the new entry, or recycle an existing one. */ node *new_node; if (_free != NULL) { @@ -298,7 +299,7 @@ template void async_list::nasync_append (V value) { new_node->_prev = _tail; _tail = new_node; } - } OSSpinLockUnlock(&_write_lock); + } os_unfair_lock_unlock(&_write_lock); } /** @@ -330,7 +331,7 @@ template void async_list::nasync_remove_first_value (V value) { */ template void async_list::nasync_remove_node (node *deleted_node) { /* Lock the list from other writers. */ - OSSpinLockLock(&_write_lock); { + os_unfair_lock_lock(&_write_lock); { /* Find the record. */ node *item = _head; while (item != NULL) { @@ -342,7 +343,7 @@ template void async_list::nasync_remove_node (node *deleted_node /* If not found, nothing to do */ if (item == NULL) { - OSSpinLockUnlock(&_write_lock); + os_unfair_lock_unlock(&_write_lock); return; } @@ -385,7 +386,7 @@ template void async_list::nasync_remove_node (node *deleted_node } else { delete item; } - } OSSpinLockUnlock(&_write_lock); + } os_unfair_lock_unlock(&_write_lock); } /** From 569d6168febc65556ebc0cfc222588622b8865f3 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:15:08 -0400 Subject: [PATCH 03/13] Replace deprecated OSMemoryBarrier usage PLCrashAsyncLinkedList.hpp:214:9: 'OSMemoryBarrier' is deprecated: first deprecated in macOS 10.12 - Use std::atomic_thread_fence() from instead --- Source/PLCrashAsyncLinkedList.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/PLCrashAsyncLinkedList.hpp b/Source/PLCrashAsyncLinkedList.hpp index e7c37ba6..cd97e3bd 100644 --- a/Source/PLCrashAsyncLinkedList.hpp +++ b/Source/PLCrashAsyncLinkedList.hpp @@ -31,6 +31,7 @@ #include "PLCrashAsync.h" #include "PLCrashMacros.h" +#include #include #include @@ -211,7 +212,7 @@ template void async_list::nasync_prepend (V value) { } /* Issue a memory barrier to ensure a consistent view of the value. */ - OSMemoryBarrier(); + std::atomic_thread_fence(std::memory_order_seq_cst); /* If this is the first entry, initialize the list. */ if (_tail == NULL) { @@ -236,7 +237,7 @@ template void async_list::nasync_prepend (V value) { _head->_prev = new_node; /* Issue a memory barrier to ensure a consistent view of the nodes. */ - OSMemoryBarrier(); + std::atomic_thread_fence(std::memory_order_seq_cst); /* Atomically slot the new record into place; this may be iterated on by a lockless reader. */ if (!OSAtomicCompareAndSwapPtrBarrier(new_node->_next, new_node, (void **) (&_head))) { @@ -272,7 +273,7 @@ template void async_list::nasync_append (V value) { } /* Issue a memory barrier to ensure a consistent view of the value. */ - OSMemoryBarrier(); + std::atomic_thread_fence(std::memory_order_seq_cst); /* If this is the first entry, initialize the list. */ if (_tail == NULL) { From 5364ec115c047cdad15550cd14e5df394939c17b Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:20:03 -0400 Subject: [PATCH 04/13] Replace deprecated OSAtomicCompareAndSwap32 PLCrashReporter.m:376:10: 'OSAtomicCompareAndSwap32' is deprecated: first deprecated in macOS 10.12 - Use atomic_compare_exchange_strong_explicit(memory_order_relaxed) from instead --- Source/PLCrashReporter.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/PLCrashReporter.m b/Source/PLCrashReporter.m index d98e2580..36a55f67 100644 --- a/Source/PLCrashReporter.m +++ b/Source/PLCrashReporter.m @@ -50,6 +50,7 @@ #import #import #import +#import #define NSDEBUG(msg, args...) {\ NSLog(@"[PLCrashReporter] " msg, ## args); \ @@ -372,8 +373,13 @@ static void uncaught_exception_handler (NSException *exception) { * It is possible that another crash may occur between setting the uncaught * exception field, and triggering the signal handler. */ - static int32_t exception_is_handled = 0; - if (!OSAtomicCompareAndSwap32(0, 1, &exception_is_handled)) { + static _Atomic int32_t exception_is_handled = 0; + int32_t expected = 0; + if (!atomic_compare_exchange_strong_explicit(&exception_is_handled, + &expected, + 1, + memory_order_relaxed, + memory_order_relaxed)) { return; } From e3aad2f35c3e52c6c797afcdafe4c59fc7af1dc6 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:22:04 -0400 Subject: [PATCH 05/13] Replace deprecated usage of OSAtomicCompareAndSwapPtrBarrier --- Source/PLCrashAsyncLinkedList.hpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Source/PLCrashAsyncLinkedList.hpp b/Source/PLCrashAsyncLinkedList.hpp index cd97e3bd..fe4018db 100644 --- a/Source/PLCrashAsyncLinkedList.hpp +++ b/Source/PLCrashAsyncLinkedList.hpp @@ -151,6 +151,17 @@ class async_list { } private: + static inline bool cas_ptr_barrier (node **target, node *expected, node *desired) { + node *expected_value = expected; + return std::atomic_compare_exchange_strong_explicit( + reinterpret_cast *>(target), + &expected_value, + desired, + std::memory_order_seq_cst, + std::memory_order_seq_cst + ); + } + void free_list (node *next); /** The lock used by writers. No lock is required for readers. */ @@ -221,7 +232,7 @@ template void async_list::nasync_prepend (V value) { _tail = new_node; /* Atomically update the list head; this will be iterated upon by lockless readers. */ - if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new_node, (void **) (&_head))) { + if (!cas_ptr_barrier(&_head, NULL, new_node)) { /* Should never occur */ PLCF_DEBUG("An async image head was set with tail == NULL despite holding lock."); } @@ -240,7 +251,7 @@ template void async_list::nasync_prepend (V value) { std::atomic_thread_fence(std::memory_order_seq_cst); /* Atomically slot the new record into place; this may be iterated on by a lockless reader. */ - if (!OSAtomicCompareAndSwapPtrBarrier(new_node->_next, new_node, (void **) (&_head))) { + if (!cas_ptr_barrier(&_head, new_node->_next, new_node)) { PLCF_DEBUG("Failed to prepend to image list despite holding lock"); } } @@ -282,7 +293,7 @@ template void async_list::nasync_append (V value) { _tail = new_node; /* Atomically update the list head; this will be iterated upon by lockless readers. */ - if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new_node, (void **) (&_head))) { + if (!cas_ptr_barrier(&_head, NULL, new_node)) { /* Should never occur */ PLCF_DEBUG("An async image head was set with tail == NULL despite holding lock."); } @@ -291,7 +302,7 @@ template void async_list::nasync_append (V value) { /* Otherwise, append to the end of the list */ else { /* Atomically slot the new record into place; this may be iterated on by a lockless reader. */ - if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new_node, (void **) (&_tail->_next))) { + if (!cas_ptr_barrier(&_tail->_next, NULL, new_node)) { PLCF_DEBUG("Failed to append to image list despite holding lock"); } @@ -354,12 +365,12 @@ template void async_list::nasync_remove_node (node *deleted_node * This serves as a synchronization point -- after the CAS, the item is no longer reachable via the list. */ if (item == _head) { - if (!OSAtomicCompareAndSwapPtrBarrier(item, item->_next, (void **) &_head)) { + if (!cas_ptr_barrier(&_head, item, item->_next)) { PLCF_DEBUG("Failed to remove image list head despite holding lock"); } } else { /* There MUST be a non-NULL prev pointer, as this is not HEAD. */ - if (!OSAtomicCompareAndSwapPtrBarrier(item, item->_next, (void **) &item->_prev->_next)) { + if (!cas_ptr_barrier(&item->_prev->_next, item, item->_next)) { PLCF_DEBUG("Failed to remove image list item despite holding lock"); } } From 6063c50d688457b66ab59895d0560f7034b15572 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:24:20 -0400 Subject: [PATCH 06/13] Replace usage of OSAtomicCompareAndSwap32Barrier PLCrashMachExceptionServer.m:808:5 'OSAtomicCompareAndSwap32Barrier' is deprecated: first deprecated in macOS 10.12 - Use atomic_compare_exchange_strong() from instead --- Source/PLCrashMachExceptionServer.m | 13 +++++++++---- Source/PLCrashReport.m | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Source/PLCrashMachExceptionServer.m b/Source/PLCrashMachExceptionServer.m index ccad4c51..4655879a 100644 --- a/Source/PLCrashMachExceptionServer.m +++ b/Source/PLCrashMachExceptionServer.m @@ -88,7 +88,7 @@ #import "PLCrashAsync.h" #import -#import +#import #import #import @@ -189,7 +189,7 @@ static exception_mask_t exception_to_mask (exception_type_t exception) { * This value must be updated atomically and with a memory barrier, as it will be accessed * without locking. */ - uint32_t server_should_stop; + _Atomic uint32_t server_should_stop; /** Intended to be observed by the waiting initialization thread. Informs * the waiting thread that shutdown has completed . */ @@ -719,7 +719,7 @@ kern_return_t PLCrashMachExceptionForward (task_t task, /* We intentionally do not acquire a lock here. It is possible that we've been woken * spuriously with the process in an unknown state, in which case we must not call * out to non-async-safe functions */ - if (exc_context->server_should_stop) { + if (atomic_load_explicit(&exc_context->server_should_stop, memory_order_seq_cst)) { /* Inform the requesting thread of completion */ pthread_mutex_lock(&exc_context->lock); { exc_context->server_stop_done = true; @@ -805,7 +805,12 @@ - (void) dealloc { } /* Mark the server for termination */ - OSAtomicCompareAndSwap32Barrier(0, 1, (int32_t *) &_serverContext->server_should_stop); + uint32_t expected = 0; + atomic_compare_exchange_strong_explicit(&_serverContext->server_should_stop, + &expected, + 1, + memory_order_seq_cst, + memory_order_seq_cst); /* Wake up the waiting server */ mach_msg_header_t msg; diff --git a/Source/PLCrashReport.m b/Source/PLCrashReport.m index 8312bc83..1d8bf075 100644 --- a/Source/PLCrashReport.m +++ b/Source/PLCrashReport.m @@ -340,7 +340,7 @@ - (PLCrashReportSystemInfo *) extractSystemInfo: (Plcrash__CrashReport__SystemIn * us is the deprecated architecture field. From that we will generate a * PLCrashReportProcessorInfo object so that library users don't have to * get at the architecture information multiple ways. */ - if (processorInfo == nil) { + if (processorInfo == nil) { processorInfo = [self synthesizeProcessorInfoFromArchitecture: systemInfo->architecture error: outError]; if (processorInfo == nil) return nil; From fceccb30770ab9307415d0a5aabe4a0ece8b396c Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:27:29 -0400 Subject: [PATCH 07/13] Replace usage of deprecated Gestalt PLCrashLogWriter.m:446:21 'gestaltSystemVersionMajor' is deprecated: first deprecated in macOS 10.8 - Use NSProcessInfo's operatingSystemVersion property instead. --- Source/PLCrashLogWriter.m | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/Source/PLCrashLogWriter.m b/Source/PLCrashLogWriter.m index 119e277c..06b484cf 100644 --- a/Source/PLCrashLogWriter.m +++ b/Source/PLCrashLogWriter.m @@ -439,25 +439,15 @@ plcrash_error_t plcrash_log_writer_init (plcrash_log_writer_t *writer, #elif TARGET_OS_MAC /* Mac OS X */ { - SInt32 major, minor, bugfix; - - /* Fetch the major, minor, and bugfix versions. - * Fetching the OS version should not fail. */ - if (Gestalt(gestaltSystemVersionMajor, &major) != noErr) { - PLCF_DEBUG("Could not retrieve system major version with Gestalt"); - return PLCRASH_EINTERNAL; - } - if (Gestalt(gestaltSystemVersionMinor, &minor) != noErr) { - PLCF_DEBUG("Could not retrieve system minor version with Gestalt"); - return PLCRASH_EINTERNAL; - } - if (Gestalt(gestaltSystemVersionBugFix, &bugfix) != noErr) { - PLCF_DEBUG("Could not retrieve system bugfix version with Gestalt"); - return PLCRASH_EINTERNAL; - } + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + NSOperatingSystemVersion systemVersion = processInfo.operatingSystemVersion; /* Compose the string */ - asprintf(&writer->system_info.version, "%" PRId32 ".%" PRId32 ".%" PRId32, (int32_t)major, (int32_t)minor, (int32_t)bugfix); + asprintf(&writer->system_info.version, + "%ld.%ld.%ld", + (long) systemVersion.majorVersion, + (long) systemVersion.minorVersion, + (long) systemVersion.patchVersion); } #else #error Unsupported Platform From decb651c274b8f405822a443c67c162390765aea Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:27:44 -0400 Subject: [PATCH 08/13] Replace more OSMemoryBarrier usage --- Source/PLCrashLogWriter.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/PLCrashLogWriter.m b/Source/PLCrashLogWriter.m index 06b484cf..0225d93d 100644 --- a/Source/PLCrashLogWriter.m +++ b/Source/PLCrashLogWriter.m @@ -38,7 +38,7 @@ #import -#import +#import #import "PLCrashReport.h" #import "PLCrashLogWriter.h" @@ -454,7 +454,7 @@ plcrash_error_t plcrash_log_writer_init (plcrash_log_writer_t *writer, #endif /* Ensure that any signal handler has a consistent view of the above initialization. */ - OSMemoryBarrier(); + atomic_thread_fence(memory_order_seq_cst); return PLCRASH_ESUCCESS; } @@ -489,7 +489,7 @@ void plcrash_log_writer_set_exception (plcrash_log_writer_t *writer, NSException } /* Ensure that any signal handler has a consistent view of the above initialization. */ - OSMemoryBarrier(); + atomic_thread_fence(memory_order_seq_cst); } /** From 68a5468e463c8064bf32e105f66171f2f430fd16 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Wed, 10 Jun 2026 14:35:42 -0400 Subject: [PATCH 09/13] Replace more deprecated OSAtomic method usages PLCrashAsyncImageList.cpp:209:5: 'OSAtomicCompareAndSwapPtrBarrier' is deprecated: first deprecated in macOS 10.12 - Use std::atomic_compare_exchange_strong() from instead PLCrashAsyncLinkedList.hpp:414:9: 'OSAtomicIncrement32Barrier' is deprecated: first deprecated in macOS 10.12 - Use std::atomic_fetch_add() from instead PLCrashAsyncLinkedList.hpp:417:9: 'OSAtomicDecrement32Barrier' is deprecated: first deprecated in macOS 10.12 - Use std::atomic_fetch_sub() from instead --- Source/PLCrashAsyncImageList.cpp | 10 +++++++++- Source/PLCrashAsyncLinkedList.hpp | 10 +++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Source/PLCrashAsyncImageList.cpp b/Source/PLCrashAsyncImageList.cpp index 37c779fe..6d23090f 100644 --- a/Source/PLCrashAsyncImageList.cpp +++ b/Source/PLCrashAsyncImageList.cpp @@ -33,6 +33,7 @@ #include #include #include +#include using namespace plcrash::async; @@ -206,7 +207,14 @@ plcrash_async_image_t *plcrash_async_image_list_next (plcrash_async_image_list_t /* Lazily swap in the cyclic node reference. This is pessimestic, but there's really not a better time to do it. */ plcrash_async_image_t *image = node->value(); - OSAtomicCompareAndSwapPtrBarrier(NULL, (void *) node, (void * volatile *) &image->_node); + async_list::node *expected_node = NULL; + std::atomic_compare_exchange_strong_explicit( + reinterpret_cast::node *> *>(&image->_node), + &expected_node, + node, + std::memory_order_seq_cst, + std::memory_order_seq_cst + ); return node->value(); } diff --git a/Source/PLCrashAsyncLinkedList.hpp b/Source/PLCrashAsyncLinkedList.hpp index fe4018db..ecff1dc6 100644 --- a/Source/PLCrashAsyncLinkedList.hpp +++ b/Source/PLCrashAsyncLinkedList.hpp @@ -175,7 +175,7 @@ class async_list { /** The list reference count. No nodes will be deallocated while the count is greater than 0. If the count * reaches 0, all nodes in the free list will be deallocated. */ - int32_t _refcount; + std::atomic _refcount; /** The node free list. */ node *_free; @@ -388,7 +388,7 @@ template void async_list::nasync_remove_node (node *deleted_node /* If a reader is active, place the node on the free list. The item is unreachable here when readers * aren't active, so if we have a 0 refcount, we can safely delete the item, and be sure that no * reader holds a reference to it. */ - if (_refcount > 0) { + if (_refcount.load(std::memory_order_seq_cst) > 0) { item->_prev = NULL; item->_next = _free; @@ -411,10 +411,10 @@ template void async_list::nasync_remove_node (node *deleted_node template void async_list::set_reading (bool enable) { if (enable) { /* Increment and issue a barrier. Once issued, no items will be deallocated while a reference is held. */ - OSAtomicIncrement32Barrier(&_refcount); + _refcount.fetch_add(1, std::memory_order_seq_cst); } else { /* Increment and issue a barrier. Once issued, items may again be deallocated. */ - OSAtomicDecrement32Barrier(&_refcount); + _refcount.fetch_sub(1, std::memory_order_seq_cst); } } @@ -426,7 +426,7 @@ template void async_list::set_reading (bool enable) { * @param current The current list node, or NULL to start iteration. */ template typename async_list::node *async_list::next (node *current) { - PLCF_ASSERT(_refcount > 0); + PLCF_ASSERT(_refcount.load(std::memory_order_seq_cst) > 0); if (current != NULL) return current->_next; From ee7a0f1dee3e805a9fcd6d87845ff20ae620e5e0 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Mon, 13 Jul 2026 13:14:16 -0400 Subject: [PATCH 10/13] Remove unused imports --- Source/PLCrashAsyncImageList.h | 1 - Source/PLCrashAsyncLinkedList.hpp | 1 - 2 files changed, 2 deletions(-) diff --git a/Source/PLCrashAsyncImageList.h b/Source/PLCrashAsyncImageList.h index 6be61fdd..d388e4b9 100644 --- a/Source/PLCrashAsyncImageList.h +++ b/Source/PLCrashAsyncImageList.h @@ -30,7 +30,6 @@ #define PLCRASH_ASYNC_IMAGE_LIST_H #include -#include #include #include "PLCrashAsyncMachOImage.h" diff --git a/Source/PLCrashAsyncLinkedList.hpp b/Source/PLCrashAsyncLinkedList.hpp index ecff1dc6..ed8e8c91 100644 --- a/Source/PLCrashAsyncLinkedList.hpp +++ b/Source/PLCrashAsyncLinkedList.hpp @@ -32,7 +32,6 @@ #include "PLCrashAsync.h" #include "PLCrashMacros.h" #include -#include #include PLCR_CPP_BEGIN_NS From f2268bfa2ddf75182f98be61715ed01b598d6355 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Mon, 13 Jul 2026 13:16:09 -0400 Subject: [PATCH 11/13] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- Source/PLCrashAsyncLinkedList.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/PLCrashAsyncLinkedList.hpp b/Source/PLCrashAsyncLinkedList.hpp index ed8e8c91..d8acaa84 100644 --- a/Source/PLCrashAsyncLinkedList.hpp +++ b/Source/PLCrashAsyncLinkedList.hpp @@ -152,13 +152,12 @@ class async_list { private: static inline bool cas_ptr_barrier (node **target, node *expected, node *desired) { node *expected_value = expected; - return std::atomic_compare_exchange_strong_explicit( - reinterpret_cast *>(target), - &expected_value, - desired, - std::memory_order_seq_cst, - std::memory_order_seq_cst - ); + return __atomic_compare_exchange_n(target, + &expected_value, + desired, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); } void free_list (node *next); From cd1b25a865a8651822859e9cb6b3fc5e029e3496 Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Mon, 13 Jul 2026 14:41:42 -0400 Subject: [PATCH 12/13] Use dispatch_once for this singleton setup --- Source/PLCrashReporter.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Source/PLCrashReporter.m b/Source/PLCrashReporter.m index 36a55f67..187b32a0 100644 --- a/Source/PLCrashReporter.m +++ b/Source/PLCrashReporter.m @@ -441,12 +441,10 @@ + (void) initialize { * clients should initialize a crash reporter instance directly. */ + (PLCrashReporter *) sharedReporter { - /* Once we drop 10.5 support, this may be converted to dispatch_once() */ - static OSSpinLock onceLock = OS_SPINLOCK_INIT; - OSSpinLockLock(&onceLock); { - if (sharedReporter == nil) - sharedReporter = [[PLCrashReporter alloc] initWithBundle: [NSBundle mainBundle] configuration: [PLCrashReporterConfig defaultConfiguration]]; - } OSSpinLockUnlock(&onceLock); + static dispatch_once_t once; + dispatch_once(&once, ^{ + sharedReporter = [[PLCrashReporter alloc] initWithBundle: [NSBundle mainBundle] configuration: [PLCrashReporterConfig defaultConfiguration]]; + }); return sharedReporter; } From 18b175a6489680c71626ea8215b8cc82e3390c2a Mon Sep 17 00:00:00 2001 From: Rory Hool Date: Mon, 13 Jul 2026 15:31:57 -0400 Subject: [PATCH 13/13] Potential fix for pull request finding 2 Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- Source/PLCrashAsyncImageList.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/PLCrashAsyncImageList.cpp b/Source/PLCrashAsyncImageList.cpp index 6d23090f..61b110a5 100644 --- a/Source/PLCrashAsyncImageList.cpp +++ b/Source/PLCrashAsyncImageList.cpp @@ -208,13 +208,12 @@ plcrash_async_image_t *plcrash_async_image_list_next (plcrash_async_image_list_t /* Lazily swap in the cyclic node reference. This is pessimestic, but there's really not a better time to do it. */ plcrash_async_image_t *image = node->value(); async_list::node *expected_node = NULL; - std::atomic_compare_exchange_strong_explicit( - reinterpret_cast::node *> *>(&image->_node), - &expected_node, - node, - std::memory_order_seq_cst, - std::memory_order_seq_cst - ); + __atomic_compare_exchange_n(&image->_node, + &expected_node, + node, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); return node->value(); }