Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

### Fixes

- Fix thread safety in macOS NSException capture to prevent duplicate exception reports (#7672)
- Capture transactions that finish during the launch profiling window instead of silently discarding them (#7602)
- Capture instance and class method `[NSApplication _crashOnException]` exceptions (#7510)

Expand Down
11 changes: 7 additions & 4 deletions Sources/Sentry/SentryNSExceptionCaptureHelper.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,31 @@
# import "SentryCrash.h"
# import "SentryNSExceptionCaptureHelper.h"
# import "SentrySwift.h"
# import <stdatomic.h>

@implementation SentryNSExceptionCaptureHelper

static BOOL _insideReportException = NO;
// Thread-safe flag to prevent duplicate exception captures when
// _crashOnException: is called from within reportException:
static _Atomic BOOL _insideReportException = NO;

+ (void)reportException:(NSException *)exception
{
_insideReportException = YES;
atomic_store(&_insideReportException, YES);
[self captureException:exception];
}

+ (void)reportExceptionDidFinish
{
_insideReportException = NO;
atomic_store(&_insideReportException, NO);
}

+ (void)crashOnException:(NSException *)exception
{
// When called from within reportException: (i.e., [super reportException:] internally
// dispatches to _crashOnException: when NSApplicationCrashOnExceptions is YES),
// the exception was already captured, so skip to avoid duplicate reports.
if (!_insideReportException) {
if (!atomic_load(&_insideReportException)) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

h: atomic_store/atomic_load are called in the _crashOnException: path, which runs right before abort(). C11 atomics are not on POSIX's async-signal-safe functions list.

Klaus believes it's OK to call these methods here, but I don't trust him:

  • ATOMIC_BOOL_LOCK_FREE should be 2 (always lock-free) on Apple arm64/x86_64, since _Bool is 8 bits and Clang's MaxAtomicInlineWidth is 128 bits on both architectures (Clang source, LLVM Atomics Guide)
  • If lock-free, these should compile to single CPU instructions (MOV/XCHG on x86, LDAR/STLR on ARM) — no locks, no library calls

Did double-check that it's safe to call C11 atomics in this context? If you already verified this, great — just want to make sure. We could also double-check with @supervacuus.

[self captureException:exception];
}
}
Expand Down
Loading