fix(macos): Fix thread safety in NSException capture#7672
fix(macos): Fix thread safety in NSException capture#7672
Conversation
Replace static BOOL flag with C11 atomic to prevent race conditions when multiple threads throw exceptions simultaneously. The previous implementation could allow duplicate exception captures when _crashOnException: was called from within reportException:. Key changes: - Add SentryNSExceptionCaptureHelper with atomic flag - Swizzle both reportException: and _crashOnException: methods - Remove SentryUseNSExceptionCallstackWrapper (no longer needed) - Simplify exception handling flow The atomic flag ensures thread-safe deduplication: when reportException: captures an exception and calls [super reportException:], which internally dispatches to _crashOnException:, the second call is skipped to avoid duplicate reports.
Semver Impact of This PR🟢 Patch (bug fixes) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨
Bug Fixes 🐛
Internal Changes 🔧Deps
Samples
Other
🤖 This preview updates automatically when you update the PR. |
…h-on-exception # Conflicts: # Sources/Sentry/SentryNSExceptionCaptureHelper.m
Sentry Build Distribution
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7672 +/- ##
=============================================
+ Coverage 85.307% 85.324% +0.016%
=============================================
Files 485 485
Lines 28838 28837 -1
Branches 12523 12521 -2
=============================================
+ Hits 24601 24605 +4
+ Misses 4190 4185 -5
Partials 47 47 see 6 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| b0c71c8 | 1206.29 ms | 1242.13 ms | 35.84 ms |
| e701dc8 | 1215.89 ms | 1254.06 ms | 38.17 ms |
| 88592c1 | 1221.80 ms | 1259.98 ms | 38.18 ms |
| 1b74fd4 | 1219.43 ms | 1250.17 ms | 30.73 ms |
| 6108e4c | 1212.31 ms | 1251.80 ms | 39.49 ms |
| 56c05ae | 1218.02 ms | 1253.30 ms | 35.28 ms |
| 19f3e6b | 1231.17 ms | 1257.02 ms | 25.85 ms |
| 2d1826b | 1216.96 ms | 1254.05 ms | 37.09 ms |
| d68691e | 1221.48 ms | 1248.13 ms | 26.65 ms |
| c424b6a | 1220.38 ms | 1248.18 ms | 27.80 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| b0c71c8 | 24.14 KiB | 1.08 MiB | 1.06 MiB |
| e701dc8 | 24.14 KiB | 1.06 MiB | 1.04 MiB |
| 88592c1 | 24.14 KiB | 1.12 MiB | 1.10 MiB |
| 1b74fd4 | 24.14 KiB | 1.10 MiB | 1.08 MiB |
| 6108e4c | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| 56c05ae | 24.14 KiB | 1.10 MiB | 1.08 MiB |
| 19f3e6b | 24.14 KiB | 1.10 MiB | 1.08 MiB |
| 2d1826b | 24.14 KiB | 1.12 MiB | 1.09 MiB |
| d68691e | 24.14 KiB | 1.12 MiB | 1.09 MiB |
| c424b6a | 24.14 KiB | 1.06 MiB | 1.04 MiB |
denrase
left a comment
There was a problem hiding this comment.
The initial issue here was that _crashOnException can now also be called individually, and not internally by reportException. So we additionally swizzle it.
But then in the case of reportException calling _crashOnException, we need to guard against it, that's why we have the flag.
As for concurrency, I can't find any documentation pointing to if this needs to be thread-safe, so I can't say if these NSApplication methods are only being called form the main thread.
If we'd want to do this, we'd need to make sure the individual threads have the interleaving protection, which i don't think we have with the atomic? Quick search turned up _Thread_local , but I am not familiar with it and we have not used it in the codebase.
static _Thread_local BOOL _insideReportException = NO;
Description
Adds thread-safe atomic operations to the
SentryNSExceptionCaptureHelperclass introduced in #7510, fixing a race condition in macOS exception handling.Problem
PR #7510 recently refactored macOS exception handling and introduced
SentryNSExceptionCaptureHelperwith a deduplication flag to prevent duplicate captures when_crashOnException:is called from withinreportException:.However, the flag uses a simple
static BOOL, which is not thread-safe. When multiple threads throw exceptions simultaneously, race conditions can occur:Solution
Replace
static BOOLwith C11 atomic operations:static BOOL _insideReportException→static _Atomic BOOL _insideReportExceptionatomic_store(&_insideReportException, YES/NO)atomic_load(&_insideReportException)This ensures thread-safe read-modify-write operations on the deduplication flag.
Changes
SentryNSExceptionCaptureHelper.m#import <stdatomic.h>_Atomic BOOLatomic_store()andatomic_load()for all accessesTesting
Related
Follow-up to #7510 which introduced the helper class.