diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cc59b8f81..310d274d47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Auto-suppress `SIGABRT` for uncaught managed exceptions on iOS ([#4523](https://github.com/getsentry/sentry-dotnet/pull/4523)) + ### Fixes - Fail when building Blazor WASM with Profiling. We don't support profiling in Blazor WebAssembly projects. ([#4512](https://github.com/getsentry/sentry-dotnet/pull/4512)) diff --git a/src/Sentry/Platforms/Cocoa/RuntimeMarshalManagedExceptionIntegration.cs b/src/Sentry/Platforms/Cocoa/RuntimeMarshalManagedExceptionIntegration.cs index 396221cb79..4ffee1a827 100644 --- a/src/Sentry/Platforms/Cocoa/RuntimeMarshalManagedExceptionIntegration.cs +++ b/src/Sentry/Platforms/Cocoa/RuntimeMarshalManagedExceptionIntegration.cs @@ -32,6 +32,11 @@ internal void Handle(object sender, MarshalManagedExceptionEventArgs e) if (e.Exception is { } ex) { + // The Obj-C runtime is about to abort. Tag the upcoming duplicate native SIGABRT event for filtering it + // out in ProcessOnBeforeSend. + // TODO: define "_captured_by_sentry-dotnet" as a constant somewhere + SentryCocoaSdk.ConfigureScope(scope => scope.SetTagValue("SIGABRT", "_captured_by_sentry-dotnet")); + ex.SetSentryMechanism( "Runtime.MarshalManagedException", "This exception was caught by the .NET Runtime Marshal Managed Exception global error handler. " + diff --git a/src/Sentry/Platforms/Cocoa/SentryOptions.cs b/src/Sentry/Platforms/Cocoa/SentryOptions.cs index 02ce449556..50a87e5b92 100644 --- a/src/Sentry/Platforms/Cocoa/SentryOptions.cs +++ b/src/Sentry/Platforms/Cocoa/SentryOptions.cs @@ -207,11 +207,12 @@ internal NativeOptions(SentryOptions options) /// convenient. /// /// + /// TODO: Explain auto (null) vs. true vs. false. /// Enabling this may prevent the capture of SIGABRT originating from native (not managed) code... so it may /// prevent the capture of genuine native SIGABRT errors. /// /// - public bool SuppressSignalAborts { get; set; } = false; + public bool? SuppressSignalAborts { get; set; } = null; /// /// diff --git a/src/Sentry/Platforms/Cocoa/SentrySdk.cs b/src/Sentry/Platforms/Cocoa/SentrySdk.cs index 9cd167dc0e..8cb5b41a85 100644 --- a/src/Sentry/Platforms/Cocoa/SentrySdk.cs +++ b/src/Sentry/Platforms/Cocoa/SentrySdk.cs @@ -200,25 +200,28 @@ private static CocoaSdk.SentryHttpStatusCodeRange[] GetFailedRequestStatusCodes( /// internal static CocoaSdk.SentryEvent? ProcessOnBeforeSend(SentryOptions options, CocoaSdk.SentryEvent evt, IHub hub) { - if (hub is DisabledHub) - { - return evt; - } - // When we have an unhandled managed exception, we send that to Sentry twice - once managed and once native. // The managed exception is what a .NET developer would expect, and it is sent by the Sentry.NET SDK // But we also get a native SIGABRT since it crashed the application, which is sent by the Sentry Cocoa SDK. // There should only be one exception on the event in this case - if ((options.Native.SuppressSignalAborts || options.Native.SuppressExcBadAccess) && evt.Exceptions?.Length == 1) + if (evt.Exceptions?.Length == 1) { // It will match the following characteristics var ex = evt.Exceptions[0]; + // TODO: define "_captured_by_sentry-dotnet" as a constant somewhere + if (options.Native.SuppressSignalAborts == null && ex.Type == evt.Tags?["_captured_by_sentry-dotnet"]?.ToString()) + { + options.LogDebug("Discarded {0} error ({1}). Captured as managed exception instead.", ex.Type, + ex.Value); + return null; + } + // Thankfully, sometimes we can see Xamarin's unhandled exception handler on the stack trace, so we can filter // them out. Here is the function that calls abort(), which we will use as a filter: // https://github.com/xamarin/xamarin-macios/blob/c55fbdfef95028ba03d0f7a35aebca03bd76f852/runtime/runtime.m#L1114-L1122 - if (options.Native.SuppressSignalAborts && ex.Type == "SIGABRT" && ex.Value == "Signal 6, Code 0" && + if (options.Native.SuppressSignalAborts == true && ex.Type == "SIGABRT" && ex.Value == "Signal 6, Code 0" && ex.Stacktrace?.Frames.Any(f => f.Function == "xamarin_unhandled_exception_handler") is true) { // Don't send it @@ -239,6 +242,11 @@ private static CocoaSdk.SentryHttpStatusCodeRange[] GetFailedRequestStatusCodes( } } + if (hub is DisabledHub) + { + return evt; + } + // We run our SIGABRT checks first before running managed processors. // Because we delegate to user code, we need to catch/log exceptions. try