Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #6193 +/- ##
=============================================
- Coverage 85.412% 85.390% -0.022%
=============================================
Files 487 487
Lines 29086 29104 +18
Branches 12592 12603 +11
=============================================
+ Hits 24843 24852 +9
- Misses 4193 4201 +8
- Partials 50 51 +1
... and 7 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
This reverts "Use pre-built version of sentry-cocoa SDK (#3727)" commit d179ec9 and restores the modules/sentry-cocoa Git module checked out at: getsentry/sentry-cocoa#6193
2f90356 to
ed98b04
Compare
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f194b9c | 1216.71 ms | 1249.02 ms | 32.31 ms |
| 5e2ec54 | 1199.69 ms | 1239.09 ms | 39.40 ms |
| 2c4362a | 1231.50 ms | 1255.95 ms | 24.45 ms |
| 5c68ec6 | 1233.11 ms | 1264.06 ms | 30.96 ms |
| 16b3235 | 1234.51 ms | 1257.84 ms | 23.33 ms |
| bb418da | 1227.60 ms | 1265.90 ms | 38.30 ms |
| d492bc8 | 1214.12 ms | 1242.19 ms | 28.06 ms |
| 64a365a | 1225.60 ms | 1255.49 ms | 29.89 ms |
| d8db577 | 1206.83 ms | 1244.39 ms | 37.56 ms |
| 62d9cf0 | 1228.72 ms | 1258.29 ms | 29.57 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f194b9c | 24.14 KiB | 1.12 MiB | 1.10 MiB |
| 5e2ec54 | 24.14 KiB | 1.10 MiB | 1.08 MiB |
| 2c4362a | 24.14 KiB | 1.07 MiB | 1.04 MiB |
| 5c68ec6 | 24.14 KiB | 1.13 MiB | 1.10 MiB |
| 16b3235 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| bb418da | 24.14 KiB | 1.04 MiB | 1.02 MiB |
| d492bc8 | 24.14 KiB | 1.11 MiB | 1.09 MiB |
| 64a365a | 24.14 KiB | 1.09 MiB | 1.06 MiB |
| d8db577 | 24.14 KiB | 1.06 MiB | 1.04 MiB |
| 62d9cf0 | 24.14 KiB | 1.09 MiB | 1.07 MiB |
Previous results on branch: jpnurmi/mono-interop
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 58546af | 1217.57 ms | 1248.98 ms | 31.40 ms |
| 4a46856 | 1236.53 ms | 1262.79 ms | 26.26 ms |
| 446c562 | 1227.20 ms | 1256.17 ms | 28.97 ms |
| 2488cd0 | 1215.08 ms | 1241.24 ms | 26.16 ms |
| 3a8f309 | 1223.75 ms | 1245.77 ms | 22.02 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 58546af | 24.14 KiB | 1.13 MiB | 1.11 MiB |
| 4a46856 | 24.14 KiB | 1.13 MiB | 1.10 MiB |
| 446c562 | 24.14 KiB | 1.13 MiB | 1.10 MiB |
| 2488cd0 | 24.14 KiB | 1.13 MiB | 1.11 MiB |
| 3a8f309 | 24.14 KiB | 1.13 MiB | 1.10 MiB |
Screen.Recording.2025-09-18.at.11.54.52.mov |
ed98b04 to
8559ea9
Compare
db30de0 to
dd33f14
Compare
dd33f14 to
e51c82e
Compare
|
Hey @jpnurmi what's the progress on this PR? |
|
I had quite some trouble passing the CI last time I tried. 😅 I should totally revive this because Sentry .NET is still very much in need of a solution for eliminating redundant |
be528ee to
e1a14ae
Compare
Semver Impact of This PR🟢 Patch (bug fixes) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨
Bug Fixes 🐛
Documentation 📚
Internal Changes 🔧Deps
Other
Other
🤖 This preview updates automatically when you update the PR. |
e1a14ae to
bab06c0
Compare
|
@jpnurmi added Let me know if this is actually ready to review |
Sentry Build Distribution
|
|
@itaybre thanks! @supervacuus will also take a look in the coming days. |
supervacuus
left a comment
There was a problem hiding this comment.
The biggest concern with this setup lies at the core of the approach you chose: using __attribute__((constructor)) runs counter to the SDK's entire life-cycle management.
So, while the changes are limited and easy to review, and the pain part is isolated to builds using SENTRY_CRASH_MANAGED_RUNTIME, i.e., no influence on normal SDK operation, I have to warn you about the side effects:
- Since the ctor lines up
previous <- sentryfor the .NET handler to chain on,close()/uninstall()restores our previous handler, removing the .NET handler from the chain. So any hard-fault-triggered .NET exception that comes in afterclose()will be unhandled wrt the .NET runtime. start()->close()->start()would lead to a second run that runs with Sentry but without the runtime handler.enableCrashHandler = falseno longer gates signal-handler installation
Fixing these likely requires SENTRY_CRASH_MANAGED_RUNTIME-specific uninstall/reinstall behavior, not just the ctor itself, and you could argue that none of those ever happen in downstream usage, but those are just the ones I immediately caught, and I think they highlight the cost of jumping a core concern outside the life-cycle boundary.
Add SENTRY_CRASH_MANAGED_RUNTIME compile-time flag that: - Preloads signal handlers via __attribute__((constructor)) before the managed runtime starts, ensuring correct handler chain order - Excludes EXC_MASK_BAD_ACCESS and EXC_MASK_ARITHMETIC from Mach exception monitoring (handled by the managed runtime via signals) Add ignoreNextSignal: API on PrivateSentrySDKOnly to let hybrid SDKs tell SentryCrash to skip the next occurrence of a signal on the calling thread (thread-local, one-shot). NULL-guard g_onExceptionEvent callback in handleException to prevent crash if a signal fires between preload and full sentrycrash_install. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The flag was originally needed to prevent sentrycrash_setMonitoring() from re-enabling Mach exceptions after preload. Now that the Mach exception mask is controlled at compile time via SENTRY_CRASH_MANAGED_RUNTIME in SentryCrashMonitor_MachException.c, there is no runtime state to guard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Preserve the managed runtime's signal handler chain across SDK lifecycle transitions (close/start) by skipping uninstall when not handling a crash. On the crash path, uninstall proceeds normally since the process is terminating.
b95d5a3 to
c12a651
Compare
Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_Signal.c
Outdated
Show resolved
Hide resolved
When the signal monitor is disabled under managed runtime, restore the previous handler for the signal before re-raising to prevent an infinite loop. Without SA_NODEFER, the raised signal would be re-delivered to the same handler after it returns.
The flag is redundant now that handleSignal() restores individual handlers before re-raising. uninstallSignalHandler() can be a blanket no-op under SENTRY_CRASH_MANAGED_RUNTIME.
|
@supervacuus thanks for the view! 🙏 I've addressed the close/reinstall scenario. |
|
By the way, there are integration tests prepared in sentry-dotnet. This patch fixes both scenarios with redundant native exceptions:
With this PR and expected failures removed: $ pwsh integration-test/ios.Tests.ps1
[...]
[+] /Users/jpnurmi/Projects/sentry/sentry-dotnet/integration-test/ios.Tests.ps1 180.08s (178.93s|113ms)
Tests completed in 180.08s
Tests Passed: 6, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0 |
|
Hi @philipphofmann @philprime @noahsmartin @itaybre, this PR is ready for review when you get a chance. It adds managed runtime (.NET/Mono) signal handler interop, solving a long-standing issue for .NET on iOS (getsentry/sentry-dotnet#3954). Most of it is gated behind |
|
Thanks for the review! Sounds good, I'll take a look tomorrow. P.S. The .NET ecosystem likes to own the term "managed" but technically, many other runtimes are managed too. I might rename it to |
I would prefer to avoid DOTNET in the name, just in case some other SDK needs this in the future. |
|
Fair enough, I kept |
Reset the flag on any signal delivery, not just the matching one. Prevents a stale flag from silently suppressing a later unrelated signal.
Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_Signal.c
Outdated
Show resolved
Hide resolved
Instead of returning early from the signal handler when a signal is ignored, skip crash processing and fall through to the existing restore + raise path. This avoids undefined behavior when the ignored signal originates from abort().
Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_Signal.c
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_Signal.c
Outdated
Show resolved
Hide resolved
Remove the SENTRY_CRASH_MANAGED_RUNTIME guard so ignored signals are properly re-raised regardless of the compile flag. Harmless for the non-managed case where uninstall already restored them.

📜 Description
TLDR; reorder .NET/Mono vs. Sentry Cocoa signal handlers to allow the .NET runtime to convert certain signals to managed .NET exceptions where appropriate, and chain actual native crashes to Sentry Cocoa.
Before
After:
Changes
Mostly gated by the
SENTRY_CRASH_MANAGED_RUNTIMEcompile-time flag to minimize impact on normal SDK operation:Signal handler preloading — A
__attribute__((constructor))preloads SentryCrash's signal handlers before the managed runtime starts, ensuring the correct handler chain order: managed runtime → SentryCrash → system. This lets the managed runtime handle signals like SIGSEGV (for NullReferenceException) and SIGFPE (for DivideByZeroException) before SentryCrash sees them.Mach exception mask filtering — Excludes
EXC_MASK_BAD_ACCESSandEXC_MASK_ARITHMETICfrom Mach exception monitoring, since these correspond to signals the managed runtime handles. Other Mach exceptions (EXC_BAD_INSTRUCTION, EXC_SOFTWARE, EXC_BREAKPOINT) are still monitored.ignoreNextSignal:API — New method onPrivateSentrySDKOnlythat tells SentryCrash to ignore the next occurrence of a given signal on the calling thread (thread-local, one-shot). Used by hybrid SDKs to prevent duplicate crash reports when the managed runtime is about to raise a signal (e.g. SIGABRT viaabort()) for an exception that has already been captured: https://github.com/dotnet/macios/blob/d0d53e8230a79fd505ddf7cef2642493249ccb78/runtime/runtime.m#L1003-L1011NULL-guard
g_onExceptionEvent— Prevents a crash if a signal fires between the constructor preload andsentrycrash_install().volatilecrash pointer — The+[SentrySDK crash]test method now usesvolatileto force an actual SIGSEGV instead of letting the compiler optimize the null dereference into a trap instruction (SIGTRAP).💡 Motivation and Context
Fixes redundant native crash events when using Sentry with .NET on iOS:
ApplicationException) produced a duplicate SIGABRT eventNullReferenceExceptionin AOT mode produced a duplicate EXC_BAD_ACCESS eventSee: getsentry/sentry-dotnet#3954
💚 How did you test it?
Sentry .NET integration tests for iOS:
📝 Checklist
You have to check all boxes before merging:
sendDefaultPIIis enabled.