@@ -195,15 +195,15 @@ private static CocoaSdk.SentryHttpStatusCodeRange[] GetFailedRequestStatusCodes(
195195 => ProcessOnBeforeSend ( options , evt , CurrentHub ) ;
196196
197197 /// <summary>
198- /// This overload allows us to inject an IHub for testing. During normal execution, the CurrentHub is used.
199- /// However, since this class is static, there's no easy alternative way to inject this when executing tests.
198+ /// Apply suppression logic for redundant native `SIGABRT` and `EXC_BAD_ACCESS` crash events
199+ /// that have already been captured as managed exceptions by the Sentry.NET SDK to avoid sending
200+ /// duplicate events to Sentry - once managed and once native.
201+ ///
202+ /// The managed exception is what a .NET developer would expect, and it is sent by the Sentry.NET SDK
203+ /// But we also get a native SIGABRT since it crashed the application, which is sent by the Sentry Cocoa SDK.
200204 /// </summary>
201- internal static CocoaSdk . SentryEvent ? ProcessOnBeforeSend ( SentryOptions options , CocoaSdk . SentryEvent evt , IHub hub )
205+ private static bool SuppressNativeCrash ( SentryOptions options , CocoaSdk . SentryEvent evt )
202206 {
203- // When we have an unhandled managed exception, we send that to Sentry twice - once managed and once native.
204- // The managed exception is what a .NET developer would expect, and it is sent by the Sentry.NET SDK
205- // But we also get a native SIGABRT since it crashed the application, which is sent by the Sentry Cocoa SDK.
206-
207207 // There should only be one exception on the event in this case
208208 if ( ( options . Native . SuppressSignalAborts || options . Native . SuppressExcBadAccess ) && evt . Exceptions ? . Length == 1 )
209209 {
@@ -219,7 +219,7 @@ private static CocoaSdk.SentryHttpStatusCodeRange[] GetFailedRequestStatusCodes(
219219 // Don't send it
220220 options . LogDebug ( "Discarded {0} error ({1}). Captured as managed exception instead." , ex . Type ,
221221 ex . Value ) ;
222- return null ! ;
222+ return true ;
223223 }
224224
225225 // Similar workaround for NullReferenceExceptions. We don't have any easy way to know whether the
@@ -230,10 +230,28 @@ private static CocoaSdk.SentryHttpStatusCodeRange[] GetFailedRequestStatusCodes(
230230 // Don't send it
231231 options . LogDebug ( "Discarded {0} error ({1}). Captured as managed exception instead." , ex . Type ,
232232 ex . Value ) ;
233- return null ! ;
233+ return true ;
234234 }
235235 }
236236
237+ return false ;
238+ }
239+
240+ /// <summary>
241+ /// This overload allows us to inject an IHub for testing. During normal execution, the CurrentHub is used.
242+ /// However, since this class is static, there's no easy alternative way to inject this when executing tests.
243+ /// </summary>
244+ internal static CocoaSdk . SentryEvent ? ProcessOnBeforeSend ( SentryOptions options , CocoaSdk . SentryEvent evt , IHub hub )
245+ {
246+ // Redundant native crash events must be suppressed even if the SDK is
247+ // disabled (or not yet fully initialized) to avoid sending duplicates.
248+ // https://github.com/getsentry/sentry-dotnet/pull/4521#discussion_r2347616896
249+ if ( SuppressNativeCrash ( options , evt ) )
250+ {
251+ return null ! ;
252+ }
253+
254+ // If the SDK is disabled, there are no event processors or before send to run.
237255 if ( hub is DisabledHub )
238256 {
239257 return evt ;
0 commit comments