From b44d22972b0e5ea036d3054644d5dfae0c56ca55 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 17 Mar 2021 16:03:03 +0000 Subject: [PATCH 01/20] Bypass KSCrashReport for all user-reported errors --- Bugsnag/Client/BugsnagClient.m | 42 ++++----------------------------- Tests/BugsnagClientMirrorTest.m | 3 --- 2 files changed, 5 insertions(+), 40 deletions(-) diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index dae522eba..4b429672a 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -895,7 +895,7 @@ - (void)notify:(NSException *)exception } /** - * Notify Bugsnag of an exception. Only intended for React Native/Unity use. + * Notify Bugsnag of an exception. Used for user-reported (handled) errors, React Native, and Unity. * * @param event the event * @param block Configuration block for adding additional report information @@ -903,17 +903,10 @@ - (void)notify:(NSException *)exception - (void)notifyInternal:(BugsnagEvent *_Nonnull)event block:(BugsnagOnErrorBlock)block { - if ([self shouldNotifyEvent:event withOnErrorBlock:block]) { - [self deliverEvent:event]; - [self addAutoBreadcrumbForEvent:event]; - } -} - -- (BOOL)shouldNotifyEvent:(nonnull BugsnagEvent *)event withOnErrorBlock:(nullable BugsnagOnErrorBlock)block { NSString *errorClass = event.errors.firstObject.errorClass; if ([self.configuration shouldDiscardErrorClass:errorClass]) { bsg_log_info(@"Discarding event because errorClass \"%@\" matched configuration.discardClasses", errorClass); - return NO; + return; } // enhance device information with additional metadata @@ -926,7 +919,7 @@ - (BOOL)shouldNotifyEvent:(nonnull BugsnagEvent *)event withOnErrorBlock:(nullab BOOL originalUnhandledValue = event.unhandled; @try { if (block != nil && !block(event)) { // skip notifying if callback false - return NO; + return; } } @catch (NSException *exception) { bsg_log_err(@"Error from onError callback: %@", exception); @@ -935,40 +928,15 @@ - (BOOL)shouldNotifyEvent:(nonnull BugsnagEvent *)event withOnErrorBlock:(nullab [event notifyUnhandledOverridden]; } - return YES; -} - -- (void)deliverEvent:(BugsnagEvent *)event { if (event.handledState.unhandled) { [self.sessionTracker handleUnhandledErrorEvent]; } else { [self.sessionTracker handleHandledErrorEvent]; } - // Temporary conditional until all (non-crash) events can be sent via -uploadEvent: - if (event == self.appHangEvent) { - [self.eventUploader uploadEvent:event completionHandler:nil]; - return; - } - - // apiKey not added to event JSON by default, need to add it here - // for when it is read next - NSMutableDictionary *eventOverrides = [[event toJsonWithRedactedKeys:self.configuration.redactedKeys] mutableCopy]; - eventOverrides[BSGKeyApiKey] = event.apiKey; - - // handled errors should persist any information edited by the user - // in a section within the KSCrash report so it can be read - // when the error is delivered - [self.crashSentry reportUserException:@"" - reason:@"" - handledState:[event.handledState toJson] - appState:[self.state toDictionary] - callbackOverrides:event.overrides - eventOverrides:eventOverrides - metadata:[event.metadata toDictionary] - config:self.configuration.dictionaryRepresentation]; + [self.eventUploader uploadEvent:event completionHandler:nil]; - [self.eventUploader uploadStoredEvents]; + [self addAutoBreadcrumbForEvent:event]; } // MARK: - Breadcrumbs diff --git a/Tests/BugsnagClientMirrorTest.m b/Tests/BugsnagClientMirrorTest.m index aaf9fd14f..8fbb9c2aa 100644 --- a/Tests/BugsnagClientMirrorTest.m +++ b/Tests/BugsnagClientMirrorTest.m @@ -129,7 +129,6 @@ - (void)setUp { @"appLaunchTimerFired: v24@0:8@16", @"configMetadataFile @16@0:8", @"configMetadataFromLastLaunch @16@0:8", - @"deliverEvent: v24@0:8@16", @"eventFromLastLaunch @16@0:8", @"eventUploader @16@0:8", @"generateOutOfMemoryEvent @16@0:8", @@ -151,8 +150,6 @@ - (void)setUp { @"setStarted: v20@0:8B16", @"setStarted: v20@0:8c16", @"setStateMetadataFromLastLaunch: v24@0:8@16", - @"shouldNotifyEvent:withOnErrorBlock: B32@0:8@16@?24", - @"shouldNotifyEvent:withOnErrorBlock: c32@0:8@16@?24", @"startAppHangDetector v16@0:8", @"stateMetadataFile @16@0:8", @"stateMetadataFromLastLaunch @16@0:8", From afb6685af450452e8d68e2870a944f3aa24b7096 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 17 Mar 2021 17:01:43 +0000 Subject: [PATCH 02/20] Remove KSCrash user exception reporting --- Bugsnag.xcodeproj/project.pbxproj | 20 --- Bugsnag/BugsnagCrashSentry.h | 9 -- Bugsnag/BugsnagCrashSentry.m | 25 +--- Bugsnag/Client/BugsnagClient.m | 2 +- .../Source/KSCrash/Recording/BSG_KSCrash.h | 30 ---- .../Source/KSCrash/Recording/BSG_KSCrash.m | 32 ----- .../Source/KSCrash/Recording/BSG_KSCrashC.c | 22 --- .../Source/KSCrash/Recording/BSG_KSCrashC.h | 26 ---- .../KSCrash/Recording/BSG_KSCrashReport.c | 83 +---------- .../KSCrash/Recording/BSG_KSCrashState.m | 7 +- .../KSCrash/Recording/BSG_KSCrashType.c | 1 - .../KSCrash/Recording/BSG_KSCrashType.h | 5 +- .../Recording/Sentry/BSG_KSCrashSentry.c | 12 +- .../Recording/Sentry/BSG_KSCrashSentry.h | 16 --- .../Recording/Sentry/BSG_KSCrashSentry_User.c | 134 ------------------ .../Recording/Sentry/BSG_KSCrashSentry_User.h | 89 ------------ Bugsnag/Payload/BugsnagThread+Recording.m | 22 ++- Tests/BugsnagConfigurationTests.m | 4 - Tests/KSCrash/KSCrashState_Tests.m | 13 -- 19 files changed, 29 insertions(+), 523 deletions(-) delete mode 100644 Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c delete mode 100644 Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.h diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index f8fde4563..092e13196 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -530,9 +530,6 @@ 00896A082486DAD100DC48C2 /* BSG_KSCrashSentry_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089693D2486DAD000DC48C2 /* BSG_KSCrashSentry_Private.h */; }; 00896A092486DAD100DC48C2 /* BSG_KSCrashSentry_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089693D2486DAD000DC48C2 /* BSG_KSCrashSentry_Private.h */; }; 00896A0A2486DAD100DC48C2 /* BSG_KSCrashSentry_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089693D2486DAD000DC48C2 /* BSG_KSCrashSentry_Private.h */; }; - 00896A0B2486DAD100DC48C2 /* BSG_KSCrashSentry_User.c in Sources */ = {isa = PBXBuildFile; fileRef = 0089693E2486DAD000DC48C2 /* BSG_KSCrashSentry_User.c */; }; - 00896A0C2486DAD100DC48C2 /* BSG_KSCrashSentry_User.c in Sources */ = {isa = PBXBuildFile; fileRef = 0089693E2486DAD000DC48C2 /* BSG_KSCrashSentry_User.c */; }; - 00896A0D2486DAD100DC48C2 /* BSG_KSCrashSentry_User.c in Sources */ = {isa = PBXBuildFile; fileRef = 0089693E2486DAD000DC48C2 /* BSG_KSCrashSentry_User.c */; }; 00896A0E2486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089693F2486DAD000DC48C2 /* BSG_KSCrashSentry.h */; }; 00896A0F2486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089693F2486DAD000DC48C2 /* BSG_KSCrashSentry.h */; }; 00896A102486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089693F2486DAD000DC48C2 /* BSG_KSCrashSentry.h */; }; @@ -554,9 +551,6 @@ 00896A202486DAD100DC48C2 /* BSG_KSCrashSentry.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969452486DAD000DC48C2 /* BSG_KSCrashSentry.c */; }; 00896A212486DAD100DC48C2 /* BSG_KSCrashSentry.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969452486DAD000DC48C2 /* BSG_KSCrashSentry.c */; }; 00896A222486DAD100DC48C2 /* BSG_KSCrashSentry.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969452486DAD000DC48C2 /* BSG_KSCrashSentry.c */; }; - 00896A232486DAD100DC48C2 /* BSG_KSCrashSentry_User.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969462486DAD000DC48C2 /* BSG_KSCrashSentry_User.h */; }; - 00896A242486DAD100DC48C2 /* BSG_KSCrashSentry_User.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969462486DAD000DC48C2 /* BSG_KSCrashSentry_User.h */; }; - 00896A252486DAD100DC48C2 /* BSG_KSCrashSentry_User.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969462486DAD000DC48C2 /* BSG_KSCrashSentry_User.h */; }; 00896A262486DAD100DC48C2 /* BSG_KSCrashSentry_Signal.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969472486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.h */; }; 00896A272486DAD100DC48C2 /* BSG_KSCrashSentry_Signal.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969472486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.h */; }; 00896A282486DAD100DC48C2 /* BSG_KSCrashSentry_Signal.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969472486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.h */; }; @@ -884,7 +878,6 @@ E7462914248907E500F92D67 /* BSG_KSString.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969242486DAD000DC48C2 /* BSG_KSString.c */; }; E7462915248907E500F92D67 /* BSG_KSObjC.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969252486DAD000DC48C2 /* BSG_KSObjC.c */; }; E7462916248907E500F92D67 /* BSG_KSCrashType.c in Sources */ = {isa = PBXBuildFile; fileRef = 0089692B2486DAD000DC48C2 /* BSG_KSCrashType.c */; }; - E7462917248907E500F92D67 /* BSG_KSCrashSentry_User.c in Sources */ = {isa = PBXBuildFile; fileRef = 0089693E2486DAD000DC48C2 /* BSG_KSCrashSentry_User.c */; }; E7462918248907E500F92D67 /* BSG_KSCrashSentry_Signal.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969412486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.c */; }; E7462919248907E500F92D67 /* BSG_KSCrashSentry_MachException.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969432486DAD000DC48C2 /* BSG_KSCrashSentry_MachException.c */; }; E746291A248907E500F92D67 /* BSG_KSCrashSentry.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969452486DAD000DC48C2 /* BSG_KSCrashSentry.c */; }; @@ -958,7 +951,6 @@ E746298A24890D3200F92D67 /* BSG_KSCrashSentry.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0089693F2486DAD000DC48C2 /* BSG_KSCrashSentry.h */; }; E746298B24890D3200F92D67 /* BSG_KSCrashSentry_CPPException.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 008969402486DAD000DC48C2 /* BSG_KSCrashSentry_CPPException.h */; }; E746298C24890D3200F92D67 /* BSG_KSCrashSentry_NSException.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 008969442486DAD000DC48C2 /* BSG_KSCrashSentry_NSException.h */; }; - E746298D24890D3200F92D67 /* BSG_KSCrashSentry_User.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 008969462486DAD000DC48C2 /* BSG_KSCrashSentry_User.h */; }; E746298E24890D3200F92D67 /* BSG_KSCrashSentry_Signal.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 008969472486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.h */; }; E746298F24890D3200F92D67 /* BSG_KSCrashType.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 008969482486DAD000DC48C2 /* BSG_KSCrashType.h */; }; E746299024890D3200F92D67 /* BSG_KSCrashIdentifier.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0089694A2486DAD000DC48C2 /* BSG_KSCrashIdentifier.h */; }; @@ -1071,7 +1063,6 @@ E746298A24890D3200F92D67 /* BSG_KSCrashSentry.h in CopyFiles */, E746298B24890D3200F92D67 /* BSG_KSCrashSentry_CPPException.h in CopyFiles */, E746298C24890D3200F92D67 /* BSG_KSCrashSentry_NSException.h in CopyFiles */, - E746298D24890D3200F92D67 /* BSG_KSCrashSentry_User.h in CopyFiles */, E746298E24890D3200F92D67 /* BSG_KSCrashSentry_Signal.h in CopyFiles */, E746298F24890D3200F92D67 /* BSG_KSCrashType.h in CopyFiles */, E746299024890D3200F92D67 /* BSG_KSCrashIdentifier.h in CopyFiles */, @@ -1254,7 +1245,6 @@ 0089693B2486DAD000DC48C2 /* BSG_KSCrashSentry_NSException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSG_KSCrashSentry_NSException.m; sourceTree = ""; }; 0089693C2486DAD000DC48C2 /* BSG_KSCrashSentry_MachException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashSentry_MachException.h; sourceTree = ""; }; 0089693D2486DAD000DC48C2 /* BSG_KSCrashSentry_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashSentry_Private.h; sourceTree = ""; }; - 0089693E2486DAD000DC48C2 /* BSG_KSCrashSentry_User.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BSG_KSCrashSentry_User.c; sourceTree = ""; }; 0089693F2486DAD000DC48C2 /* BSG_KSCrashSentry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashSentry.h; sourceTree = ""; }; 008969402486DAD000DC48C2 /* BSG_KSCrashSentry_CPPException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashSentry_CPPException.h; sourceTree = ""; }; 008969412486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BSG_KSCrashSentry_Signal.c; sourceTree = ""; }; @@ -1262,7 +1252,6 @@ 008969432486DAD000DC48C2 /* BSG_KSCrashSentry_MachException.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BSG_KSCrashSentry_MachException.c; sourceTree = ""; }; 008969442486DAD000DC48C2 /* BSG_KSCrashSentry_NSException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashSentry_NSException.h; sourceTree = ""; }; 008969452486DAD000DC48C2 /* BSG_KSCrashSentry.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BSG_KSCrashSentry.c; sourceTree = ""; }; - 008969462486DAD000DC48C2 /* BSG_KSCrashSentry_User.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashSentry_User.h; sourceTree = ""; }; 008969472486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashSentry_Signal.h; sourceTree = ""; }; 008969482486DAD000DC48C2 /* BSG_KSCrashType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSCrashType.h; sourceTree = ""; }; 008969492486DAD000DC48C2 /* BSG_KSCrashReport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BSG_KSCrashReport.c; sourceTree = ""; }; @@ -1644,8 +1633,6 @@ 0089693D2486DAD000DC48C2 /* BSG_KSCrashSentry_Private.h */, 008969412486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.c */, 008969472486DAD000DC48C2 /* BSG_KSCrashSentry_Signal.h */, - 0089693E2486DAD000DC48C2 /* BSG_KSCrashSentry_User.c */, - 008969462486DAD000DC48C2 /* BSG_KSCrashSentry_User.h */, 008969452486DAD000DC48C2 /* BSG_KSCrashSentry.c */, 0089693F2486DAD000DC48C2 /* BSG_KSCrashSentry.h */, ); @@ -2092,7 +2079,6 @@ 008969D22486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */, 008967D72486DA2D00DC48C2 /* BSGConfigurationBuilder.h in Headers */, 008969812486DAD100DC48C2 /* BSG_KSObjC.h in Headers */, - 00896A232486DAD100DC48C2 /* BSG_KSCrashSentry_User.h in Headers */, 008969A22486DAD100DC48C2 /* BSG_KSDynamicLinker.h in Headers */, 008969B42486DAD100DC48C2 /* BSG_KSObjCApple.h in Headers */, CBE9062A25A34DAB0045B965 /* BSGStorageMigratorV0V1.h in Headers */, @@ -2196,7 +2182,6 @@ 008969D32486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */, 008967D82486DA2D00DC48C2 /* BSGConfigurationBuilder.h in Headers */, 008969822486DAD100DC48C2 /* BSG_KSObjC.h in Headers */, - 00896A242486DAD100DC48C2 /* BSG_KSCrashSentry_User.h in Headers */, 008969A32486DAD100DC48C2 /* BSG_KSDynamicLinker.h in Headers */, 008969B52486DAD100DC48C2 /* BSG_KSObjCApple.h in Headers */, 008969942486DAD100DC48C2 /* BSG_KSLogger.h in Headers */, @@ -2300,7 +2285,6 @@ 008969D42486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */, 008967D92486DA2D00DC48C2 /* BSGConfigurationBuilder.h in Headers */, 008969832486DAD100DC48C2 /* BSG_KSObjC.h in Headers */, - 00896A252486DAD100DC48C2 /* BSG_KSCrashSentry_User.h in Headers */, 008969A42486DAD100DC48C2 /* BSG_KSDynamicLinker.h in Headers */, 008969B62486DAD100DC48C2 /* BSG_KSObjCApple.h in Headers */, 008969952486DAD100DC48C2 /* BSG_KSLogger.h in Headers */, @@ -2662,7 +2646,6 @@ 00896A202486DAD100DC48C2 /* BSG_KSCrashSentry.c in Sources */, 00AD1F272486A17900A27979 /* BugsnagCrashSentry.m in Sources */, 008968B22486DA9600DC48C2 /* BugsnagDeviceWithState.m in Sources */, - 00896A0B2486DAD100DC48C2 /* BSG_KSCrashSentry_User.c in Sources */, 0089682F2486DA5600DC48C2 /* BugsnagCollections.m in Sources */, 0089698D2486DAD100DC48C2 /* BSG_KSMach.c in Sources */, ); @@ -2833,7 +2816,6 @@ 00896A212486DAD100DC48C2 /* BSG_KSCrashSentry.c in Sources */, 00AD1F282486A17900A27979 /* BugsnagCrashSentry.m in Sources */, 008968B32486DA9600DC48C2 /* BugsnagDeviceWithState.m in Sources */, - 00896A0C2486DAD100DC48C2 /* BSG_KSCrashSentry_User.c in Sources */, 008968302486DA5600DC48C2 /* BugsnagCollections.m in Sources */, 0089698E2486DAD100DC48C2 /* BSG_KSMach.c in Sources */, ); @@ -3002,7 +2984,6 @@ 00896A222486DAD100DC48C2 /* BSG_KSCrashSentry.c in Sources */, 00AD1F292486A17900A27979 /* BugsnagCrashSentry.m in Sources */, 008968B42486DA9600DC48C2 /* BugsnagDeviceWithState.m in Sources */, - 00896A0D2486DAD100DC48C2 /* BSG_KSCrashSentry_User.c in Sources */, 008968312486DA5600DC48C2 /* BugsnagCollections.m in Sources */, 0089698F2486DAD100DC48C2 /* BSG_KSMach.c in Sources */, ); @@ -3108,7 +3089,6 @@ E7462915248907E500F92D67 /* BSG_KSObjC.c in Sources */, 01CCAEF025D414D60057268D /* BugsnagLastRunInfo.m in Sources */, E7462916248907E500F92D67 /* BSG_KSCrashType.c in Sources */, - E7462917248907E500F92D67 /* BSG_KSCrashSentry_User.c in Sources */, E7462918248907E500F92D67 /* BSG_KSCrashSentry_Signal.c in Sources */, E7462919248907E500F92D67 /* BSG_KSCrashSentry_MachException.c in Sources */, E746291A248907E500F92D67 /* BSG_KSCrashSentry.c in Sources */, diff --git a/Bugsnag/BugsnagCrashSentry.h b/Bugsnag/BugsnagCrashSentry.h index 7a5f20e27..4f3c8bac9 100644 --- a/Bugsnag/BugsnagCrashSentry.h +++ b/Bugsnag/BugsnagCrashSentry.h @@ -20,15 +20,6 @@ notifier:(BugsnagNotifier *)notifier onCrash:(BSGReportCallback)onCrash; -- (void)reportUserException:(NSString *)reportName - reason:(NSString *)reportMessage - handledState:(NSDictionary *)handledState - appState:(NSDictionary *)appState - callbackOverrides:(NSDictionary *)overrides - eventOverrides:(NSDictionary *)eventOverrides - metadata:(NSDictionary *)metadata - config:(NSDictionary *)config; - - (BSG_KSCrashType)mapKSToBSGCrashTypes:(BugsnagErrorTypes *)errorTypes; @end diff --git a/Bugsnag/BugsnagCrashSentry.m b/Bugsnag/BugsnagCrashSentry.m index fc23b5ccb..0c43a11ea 100644 --- a/Bugsnag/BugsnagCrashSentry.m +++ b/Bugsnag/BugsnagCrashSentry.m @@ -32,8 +32,8 @@ - (void)install:(BugsnagConfiguration *)config // applies to unhandled errors ksCrash.threadTracingEnabled = config.sendThreads != BSGThreadSendPolicyNever; - // User reported events are *always* handled - BSG_KSCrashType crashTypes = BSG_KSCrashTypeUserReported; + // User reported events do not go through KSCrash + BSG_KSCrashType crashTypes = 0; // If Bugsnag is autodetecting errors then the types of event detected is configurable // (otherwise it's just the user reported events) @@ -65,25 +65,4 @@ - (BSG_KSCrashType)mapKSToBSGCrashTypes:(BugsnagErrorTypes *)errorTypes | (errorTypes.machExceptions ? BSG_KSCrashTypeMachException : 0)); } -- (void)reportUserException:(NSString *)reportName - reason:(NSString *)reportMessage - handledState:(NSDictionary *)handledState - appState:(NSDictionary *)appState - callbackOverrides:(NSDictionary *)overrides - eventOverrides:(NSDictionary *)eventOverrides - metadata:(NSDictionary *)metadata - config:(NSDictionary *)config { - [[BSG_KSCrash sharedInstance] reportUserException:reportName - reason:reportMessage - handledState:handledState - appState:appState - callbackOverrides:overrides - eventOverrides:eventOverrides - metadata:metadata - config:config]; - - bsg_log_debug(@"Saved KSCrashReport for \"%@\" \"%@\"", handledState[@"severityReasonType"], - [[eventOverrides[@"exceptions"] firstObject] valueForKey:@"errorClass"]); -} - @end diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index 4b429672a..de9063c16 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -124,7 +124,7 @@ - (NSDictionary *)BSG_mergedInto:(NSDictionary *)dest; * @param writer report writer which will receive updated metadata */ void BSSerializeDataCrashHandler(const BSG_KSCrashReportWriter *writer, int type) { - BOOL isCrash = BSG_KSCrashTypeUserReported != type; + BOOL isCrash = YES; if (hasRecordedSessions) { // a session is available // persist session info writer->addStringElement(writer, "id", (const char *) sessionId); diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h index 224673a55..022f089c9 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h @@ -71,31 +71,6 @@ */ - (BOOL)install:(NSString *)directory; -/** Report a custom, user defined exception. - * This can be useful when dealing with scripting languages. - * - * If terminateProgram is true, all sentries will be uninstalled and the - * application will terminate with an abort(). - * - * @param name The exception name (for namespacing exception types). - * @param reason A description of why the exception occurred - * @param handledState The severity, reason, and handled-ness of the report - * @param appState breadcrumbs and other app environmental info - * @param overrides Report fields overridden by callbacks, collated in the - * final report - * @param eventOverrides the Bugsnag Error Payload, for handled errors only - * @param metadata additional information to attach to the report - * @param config delivery options - */ -- (void)reportUserException:(NSString *)name - reason:(NSString *)reason - handledState:(NSDictionary *)handledState - appState:(NSDictionary *)appState - callbackOverrides:(NSDictionary *)overrides - eventOverrides:(NSDictionary *)eventOverrides - metadata:(NSDictionary *)metadata - config:(NSDictionary *)config; - /** * Collects information about the application's foreground state (duration in foreground/background) */ @@ -112,11 +87,6 @@ */ @property(nonatomic, readwrite, assign) BOOL threadTracingEnabled; -/** - * If YES, binary images will be collected for each report. - */ -@property(nonatomic, readwrite, assign) BOOL writeBinaryImagesForUserReported; - @end //! Project version number for BSG_KSCrashFramework. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m index ff0ccae75..810b33621 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m @@ -99,8 +99,6 @@ @implementation BSG_KSCrash @synthesize maxStoredReports = _maxStoredReports; @synthesize reportWhenDebuggerIsAttached = _reportWhenDebuggerIsAttached; @synthesize threadTracingEnabled = _threadTracingEnabled; -@synthesize writeBinaryImagesForUserReported = - _writeBinaryImagesForUserReported; // ============================================================================ #pragma mark - Lifecycle - @@ -121,9 +119,7 @@ - (instancetype)init { self.nextCrashID = [NSUUID UUID].UUIDString; self.introspectMemory = YES; self.maxStoredReports = 5; - self.reportWhenDebuggerIsAttached = NO; - self.writeBinaryImagesForUserReported = YES; } return self; } @@ -179,13 +175,6 @@ - (void)setThreadTracingEnabled:(BOOL)threadTracingEnabled { bsg_kscrash_setThreadTracingEnabled(threadTracingEnabled); } -- (void)setWriteBinaryImagesForUserReported: - (BOOL)writeBinaryImagesForUserReported { - _writeBinaryImagesForUserReported = writeBinaryImagesForUserReported; - bsg_kscrash_setWriteBinaryImagesForUserReported( - writeBinaryImagesForUserReported); -} - - (BOOL)install:(NSString *)directory { bsg_kscrash_generate_report_initialize(directory.fileSystemRepresentation, self.bundleName.UTF8String); char *crashReportPath = (char *)bsg_kscrash_generate_report_path(self.nextCrashID.UTF8String, false); @@ -255,27 +244,6 @@ - (NSDictionary *)captureAppStats { return dict; } -- (void)reportUserException:(NSString *)name - reason:(NSString *)reason - handledState:(NSDictionary *)handledState - appState:(NSDictionary *)appState - callbackOverrides:(NSDictionary *)overrides - eventOverrides:(NSDictionary *)eventOverrides - metadata:(NSDictionary *)metadata - config:(NSDictionary *)config { - const char *cName = [name cStringUsingEncoding:NSUTF8StringEncoding]; - const char *cReason = [reason cStringUsingEncoding:NSUTF8StringEncoding]; - - bsg_kscrash_reportUserException(cName, cReason, - [handledState[@"currentSeverity"] UTF8String], - [self encodeAsJSONString:handledState], - [self encodeAsJSONString:overrides], - [self encodeAsJSONString:eventOverrides], - [self encodeAsJSONString:metadata], - [self encodeAsJSONString:appState], - [self encodeAsJSONString:config]); -} - // ============================================================================ #pragma mark - Advanced API - // ============================================================================ diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c index c85dc6d51..a8f9d59e2 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c @@ -27,7 +27,6 @@ #include "BSG_KSCrashC.h" #include "BSG_KSCrashReport.h" -#include "BSG_KSCrashSentry_User.h" #include "BSG_KSMach.h" #include "BSG_KSMachHeaders.h" #include "BSG_KSObjC.h" @@ -188,27 +187,6 @@ void bsg_kscrash_setCrashNotifyCallback( crashContext()->config.onCrashNotify = onCrashNotify; } -void bsg_kscrash_reportUserException(const char *name, const char *reason, - const char *severity, - const char *handledState, - const char *overrides, - const char *eventOverrides, - const char *metadata, - const char *appState, - const char *config) { - bsg_kscrashsentry_reportUserException(name, reason, - severity, - handledState, overrides, - eventOverrides, - metadata, appState, config); -} - -void bsg_kscrash_setWriteBinaryImagesForUserReported( - bool writeBinaryImagesForUserReported) { - crashContext()->crash.writeBinaryImagesForUserReported = - writeBinaryImagesForUserReported; -} - void bsg_kscrash_setReportWhenDebuggerIsAttached( bool reportWhenDebuggerIsAttached) { crashContext()->crash.reportWhenDebuggerIsAttached = diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h index cb1bfd6e0..0b26f5d1b 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h @@ -123,29 +123,6 @@ void bsg_kscrash_setIntrospectMemory(bool introspectMemory); void bsg_kscrash_setCrashNotifyCallback( const BSGReportCallback onCrashNotify); -/** Report a custom, user defined exception. - * This can be useful when dealing with scripting languages. - * - * If terminateProgram is true, all sentries will be uninstalled and the - * application will terminate with an abort(). - * - * @param name The exception name (for namespacing exception types). - * @param reason A description of why the exception occurred. - * @param handledState The severity, reason, and handled-ness of the report - * @param appState breadcrumbs and other app environmental info - * @param overrides Report fields overridden by callbacks, collated in the - * final report - * @param metadata additional information to attach to the report - */ -void bsg_kscrash_reportUserException(const char *name, const char *reason, - const char *severity, - const char *handledState, - const char *overrides, - const char *eventOverrides, - const char *metadata, - const char *appState, - const char *config); - /** If YES, user reported exceptions even if a debugger is attached * * Default: NO @@ -155,9 +132,6 @@ void bsg_kscrash_setReportWhenDebuggerIsAttached( void bsg_kscrash_setThreadTracingEnabled(bool threadTracingEnabled); -void bsg_kscrash_setWriteBinaryImagesForUserReported( - bool writeBinaryImagesForUserReported); - /** * The current crash context */ diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c index fbe5801e5..bf81673ea 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c @@ -432,8 +432,7 @@ uintptr_t *bsg_kscrw_i_getBacktrace( if (thread == crash->offendingThread) { if (crash->stackTrace != NULL && crash->stackTraceLength > 0 && (crash->crashType & - (BSG_KSCrashTypeCPPException | BSG_KSCrashTypeNSException | - BSG_KSCrashTypeUserReported))) { + (BSG_KSCrashTypeCPPException | BSG_KSCrashTypeNSException))) { *backtraceLength = crash->stackTraceLength; return crash->stackTrace; } @@ -523,11 +522,6 @@ void bsg_kscrw_i_logCrashType( sigName, sigCodeName, sentryContext->faultAddress); break; } - case BSG_KSCrashTypeUserReported: { - BSG_KSLOG_INFO("App crashed due to user specified exception: %s", - sentryContext->crashReason); - break; - } } } @@ -633,10 +627,6 @@ bool bsg_kscrw_i_exceedsBufferLen(const size_t length); void bsg_kscrashreport_writeKSCrashFields(BSG_KSCrash_Context *crashContext, BSG_KSCrashReportWriter *writer); -void bsg_kscrashreport_writeBugsnagPayload(const BSG_KSCrash_Context *crashContext, const BSG_KSCrashReportWriter *writer); - -void bsg_kscrashreport_writeOverrides(const BSG_KSCrash_Context *crashContext, const BSG_KSCrashReportWriter *writer); - /** Write the contents of a memory location. * Also writes meta information about the data. * @@ -1245,11 +1235,6 @@ void bsg_kscrw_i_writeError(const BSG_KSCrashReportWriter *const writer, sigCode = crash->signal.signalInfo->si_code; machExceptionType = bsg_kssignal_machExceptionForSignal(sigNum); break; - case BSG_KSCrashTypeUserReported: - machExceptionType = EXC_CRASH; - sigNum = SIGABRT; - crashReason = crash->crashReason; - break; } const char *machExceptionName = bsg_ksmachexceptionName(machExceptionType); @@ -1261,7 +1246,7 @@ void bsg_kscrw_i_writeError(const BSG_KSCrashReportWriter *const writer, writer->beginObject(writer, key); { - if (BSG_KSCrashTypeUserReported != crash->crashType) { + if (crash->crashType) { writer->addUIntegerElement(writer, BSG_KSCrashField_Address, crash->faultAddress); } @@ -1346,18 +1331,6 @@ void bsg_kscrw_i_writeError(const BSG_KSCrashReportWriter *const writer, writer->addStringElement(writer, BSG_KSCrashField_Type, BSG_KSCrashExcType_Signal); break; - - case BSG_KSCrashTypeUserReported: { - writer->addStringElement(writer, BSG_KSCrashField_Type, - BSG_KSCrashExcType_User); - writer->beginObject(writer, BSG_KSCrashField_UserReported); - { - writer->addStringElement(writer, BSG_KSCrashField_Name, - crash->userException.name); - } - writer->endContainer(writer); - break; - } } } writer->endContainer(writer); @@ -1581,19 +1554,13 @@ void bsg_kscrashreport_writeStandardReport( bsg_ksjsonbeginEncode(bsg_getJsonContext(writer), false, bsg_kscrw_i_addJSONData, &fd); - // KSCrash report fields are not required for handled errors as - // they serialize info in the bugsnag payload JSON schema instead. - bool recordKSCrashFields = crashContext->crash.userException.eventOverrides == NULL; - writer->beginObject(writer, BSG_KSCrashField_Report); { bsg_kscrw_i_writeReportInfo( writer, BSG_KSCrashField_Report, BSG_KSCrashReportType_Standard, crashContext->config.crashID, crashContext->config.processName); - if (recordKSCrashFields) { - bsg_kscrashreport_writeKSCrashFields(crashContext, writer); - } + bsg_kscrashreport_writeKSCrashFields(crashContext, writer); if (crashContext->config.onCrashNotify != NULL) { // NOTE: The deny list for BSG_KSCrashField_UserAtCrash children in BugsnagEvent.m @@ -1601,17 +1568,6 @@ void bsg_kscrashreport_writeStandardReport( // Write handled exception report info writer->beginObject(writer, BSG_KSCrashField_UserAtCrash); - if (crashContext->crash.crashType == BSG_KSCrashTypeUserReported) { - if (crashContext->crash.userException.overrides != NULL) { - writer->addJSONElement(writer, BSG_KSCrashField_Overrides, - crashContext->crash.userException.overrides); - } - if (recordKSCrashFields) { - bsg_kscrashreport_writeOverrides(crashContext, writer); - } else { - bsg_kscrashreport_writeBugsnagPayload(crashContext, writer); - } - } { bsg_kscrw_i_callUserCrashHandler(crashContext, writer); } writer->endContainer(writer); } @@ -1623,34 +1579,6 @@ void bsg_kscrashreport_writeStandardReport( close(fd); } -void bsg_kscrashreport_writeBugsnagPayload(const BSG_KSCrash_Context *crashContext, - const BSG_KSCrashReportWriter *writer) { - if (crashContext->crash.userException.eventOverrides != NULL) { - writer->addJSONElement(writer, BSG_KSCrashField_EventJson, - crashContext->crash.userException.eventOverrides); - } -} - -void bsg_kscrashreport_writeOverrides(const BSG_KSCrash_Context *crashContext, - const BSG_KSCrashReportWriter *writer) { - if (crashContext->crash.userException.handledState != NULL) { - writer->addJSONElement(writer, BSG_KSCrashField_HandledState, - crashContext->crash.userException.handledState); - } - if (crashContext->crash.userException.metadata != NULL) { - writer->addJSONElement(writer, BSG_KSCrashField_Metadata, - crashContext->crash.userException.metadata); - } - if (crashContext->crash.userException.state != NULL) { - writer->addJSONElement(writer, BSG_KSCrashField_State, - crashContext->crash.userException.state); - } - if (crashContext->crash.userException.config != NULL) { - writer->addJSONElement(writer, BSG_KSCrashField_Config, - crashContext->crash.userException.config); - } -} - void bsg_kscrashreport_writeKSCrashFields(BSG_KSCrash_Context *crashContext, BSG_KSCrashReportWriter *writer) { bsg_kscrw_i_writeProcessState(writer, BSG_KSCrashField_ProcessState); @@ -1684,10 +1612,7 @@ void bsg_kscrw_i_writeTraceInfo(const BSG_KSCrash_Context *crashContext, const BSG_KSCrashReportWriter *writer) { const BSG_KSCrash_SentryContext *crash = &crashContext->crash; - // Don't write the binary images for user reported crashes to improve performance - if (crash->writeBinaryImagesForUserReported == true || crash->crashType != BSG_KSCrashTypeUserReported) { - bsg_kscrw_i_writeBinaryImages(writer, BSG_KSCrashField_BinaryImages); - } + bsg_kscrw_i_writeBinaryImages(writer, BSG_KSCrashField_BinaryImages); writer->beginObject(writer, BSG_KSCrashField_Crash); { bsg_kscrw_i_writeAllThreads(writer, BSG_KSCrashField_Threads, crash, diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m index e800031e1..8d09ecbdd 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m @@ -350,11 +350,8 @@ void bsg_kscrashstate_notifyAppCrash(BSG_KSCrashType type) { BSG_KSCrash_State *const state = bsg_g_state; const char *const stateFilePath = bsg_g_stateFilePath; bsg_kscrashstate_updateDurationStats(state); - BOOL didCrash = type != BSG_KSCrashTypeUserReported; - state->crashedThisLaunch |= didCrash; - if (didCrash) { - bsg_kscrashstate_i_saveState(state, stateFilePath); - } + state->crashedThisLaunch = YES; + bsg_kscrashstate_i_saveState(state, stateFilePath); } void bsg_kscrashstate_updateDurationStats(BSG_KSCrash_State *const state) { diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.c index 15824b913..534341ce4 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.c @@ -36,7 +36,6 @@ static const struct { BSG_CRASHTYPE(BSG_KSCrashTypeSignal), BSG_CRASHTYPE(BSG_KSCrashTypeCPPException), BSG_CRASHTYPE(BSG_KSCrashTypeNSException), - BSG_CRASHTYPE(BSG_KSCrashTypeUserReported), }; static const int bsg_g_crashTypesCount = sizeof(bsg_g_crashTypes) / sizeof(*bsg_g_crashTypes); diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.h index 84baad384..d52dcf0e6 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.h @@ -32,7 +32,6 @@ * - Fatal signal * - Uncaught C++ exception * - Uncaught Objective-C NSException - * - User reported custom exception */ @@ -41,13 +40,11 @@ typedef CF_ENUM(unsigned, BSG_KSCrashType) { BSG_KSCrashTypeSignal = 0x02, BSG_KSCrashTypeCPPException = 0x04, BSG_KSCrashTypeNSException = 0x08, - BSG_KSCrashTypeUserReported = 0x20, }; #define BSG_KSCrashTypeAll \ (BSG_KSCrashTypeMachException | BSG_KSCrashTypeSignal | \ - BSG_KSCrashTypeCPPException | BSG_KSCrashTypeNSException | \ - BSG_KSCrashTypeUserReported) + BSG_KSCrashTypeCPPException | BSG_KSCrashTypeNSException) #define BSG_KSCrashTypeDebuggerUnsafe \ (BSG_KSCrashTypeMachException | BSG_KSCrashTypeNSException) diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c index 5932550df..10655e6ee 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c @@ -33,7 +33,6 @@ #include "BSG_KSCrashSentry_NSException.h" #include "BSG_KSCrashSentry_MachException.h" #include "BSG_KSCrashSentry_Signal.h" -#include "BSG_KSCrashSentry_User.h" #include "BSG_KSLogger.h" #include "BSG_KSMach.h" @@ -67,11 +66,6 @@ static BSG_CrashSentry bsg_g_sentries[] = { BSG_KSCrashTypeNSException, bsg_kscrashsentry_installNSExceptionHandler, bsg_kscrashsentry_uninstallNSExceptionHandler, }, - { - BSG_KSCrashTypeUserReported, - bsg_kscrashsentry_installUserExceptionHandler, - bsg_kscrashsentry_uninstallUserExceptionHandler, - }, }; static size_t bsg_g_sentriesCount = sizeof(bsg_g_sentries) / sizeof(*bsg_g_sentries); @@ -102,7 +96,7 @@ bsg_kscrashsentry_installWithContext(BSG_KSCrash_SentryContext *context, } else { BSG_KSLOG_WARN("App is running in a debugger. Only handled " "events will be sent to Bugsnag."); - crashTypes = BSG_KSCrashTypeUserReported; + crashTypes = 0; } } else { BSG_KSLOG_DEBUG( @@ -204,16 +198,12 @@ void bsg_kscrashsentry_clearContext(BSG_KSCrash_SentryContext *context) { void (*onCrash)(void *) = context->onCrash; bool threadTracingEnabled = context->threadTracingEnabled; bool reportWhenDebuggerIsAttached = context->reportWhenDebuggerIsAttached; - bool writeBinaryImagesForUserReported = - context->writeBinaryImagesForUserReported; memset(context, 0, sizeof(*context)); context->onCrash = onCrash; context->threadTracingEnabled = threadTracingEnabled; context->reportWhenDebuggerIsAttached = reportWhenDebuggerIsAttached; - context->writeBinaryImagesForUserReported = - writeBinaryImagesForUserReported; } void bsg_kscrashsentry_beginHandlingCrash(BSG_KSCrash_SentryContext *context) { diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h index 25bf02719..6f1a13632 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h @@ -63,9 +63,6 @@ typedef struct BSG_KSCrash_SentryContext { */ bool threadTracingEnabled; - /** If true, will record binary images. */ - bool writeBinaryImagesForUserReported; - // Implementation defined values. Caller does not initialize these. /** Threads reserved by the crash handlers, which must not be suspended. */ @@ -135,19 +132,6 @@ typedef struct BSG_KSCrash_SentryContext { const siginfo_t *signalInfo; } signal; - struct { - /** The exception name. */ - const char *name; - - /** Handled exception report info: */ - const char *overrides; // info set in callbacks - const char *eventOverrides; // Bugsnag Error API JSON payload for handled events - const char *handledState; - const char *metadata; - const char *state; // breadcrumbs, other shared app state - const char *config; // config options which affect report delivery - } userException; - } BSG_KSCrash_SentryContext; /** Install crash sentry. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c deleted file mode 100644 index 8aed3032e..000000000 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c +++ /dev/null @@ -1,134 +0,0 @@ -// -// BSG_KSCrashSentry_User.c -// -// Copyright (c) 2012 Karl Stenerud. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall remain in place -// in this source code. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#include "BSG_KSCrashSentry_User.h" -#include "BSG_KSCrashSentry_Private.h" -#include "BSG_KSMach.h" -#include "BSG_KSCrashC.h" -#include "BSG_KSCrashIdentifier.h" - -//#define BSG_KSLogger_LocalLevel TRACE -#include "BSG_KSLogger.h" - -#include -#include - -/** Context to fill with crash information. */ -static BSG_KSCrash_SentryContext *bsg_g_context; - -/** Lock for suspending threads from reportUserException() */ -static pthread_mutex_t bsg_suspend_threads_mutex = PTHREAD_MUTEX_INITIALIZER; - -bool bsg_kscrashsentry_installUserExceptionHandler( - BSG_KSCrash_SentryContext *const context) { - BSG_KSLOG_DEBUG("Installing user exception handler."); - bsg_g_context = context; - return true; -} - -void bsg_kscrashsentry_uninstallUserExceptionHandler(void) { - BSG_KSLOG_DEBUG("Uninstalling user exception handler."); - bsg_g_context = NULL; -} - -/** - * Copies the global crash context, setting new crash report paths - */ -BSG_KSCrash_Context *bsg_kscrashsentry_generateReportContext() { - BSG_KSCrash_Context *localContext = malloc(sizeof(BSG_KSCrash_Context)); - if (!localContext) { - return NULL; - } - memcpy(localContext, crashContext(), sizeof(BSG_KSCrash_Context)); - localContext->config.crashID = bsg_kscrash_generate_report_identifier(); - localContext->config.crashReportFilePath = - bsg_kscrash_generate_report_path(localContext->config.crashID, false); - localContext->config.recrashReportFilePath = - bsg_kscrash_generate_report_path(localContext->config.crashID, true); - - return localContext; -} - -/** - * Frees a crash context - */ -void bsg_kscrashsentry_freeReportContext(BSG_KSCrash_Context *context) { - free((void *)context->config.crashID); - free((void *)context->config.crashReportFilePath); - free((void *)context->config.recrashReportFilePath); - free(context); -} - -void bsg_kscrashsentry_reportUserException(const char *name, const char *reason, - const char *severity, - const char *handledState, - const char *overrides, - const char *eventOverrides, - const char *metadata, - const char *appState, - const char *config) { - if (bsg_g_context == NULL) { - BSG_KSLOG_WARN("User-reported exception sentry is not installed. " - "Exception has not been recorded."); - } else { - BSG_KSCrash_Context *reportContext = bsg_kscrashsentry_generateReportContext(); - BSG_KSCrash_SentryContext *localContext = &reportContext->crash; - - BSG_KSLOG_DEBUG("Filling out context."); - localContext->stackTraceLength = 0; - localContext->crashType = BSG_KSCrashTypeUserReported; - localContext->offendingThread = bsg_ksmachthread_self(); - localContext->registersAreValid = false; - localContext->crashReason = reason; - localContext->userException.name = name; - localContext->userException.handledState = handledState; - localContext->userException.overrides = overrides; - localContext->userException.config = config; - localContext->userException.metadata = metadata; - localContext->userException.state = appState; - localContext->userException.eventOverrides = eventOverrides; - - BSG_KSLOG_DEBUG("Calling main crash handler."); - localContext->onCrash(reportContext); - - bsg_kscrashsentry_freeReportContext(reportContext); - } -} - -void bsg_kscrashsentry_suspend_threads_user() { - pthread_mutex_lock(&bsg_suspend_threads_mutex); - BSG_KSLOG_DEBUG("Suspending all threads"); - bsg_kscrashsentry_suspendThreads(); -} - -void bsg_kscrashsentry_resume_threads_user(bool terminateProgram) { - if (terminateProgram) { - bsg_kscrashsentry_uninstall(BSG_KSCrashTypeAll); - bsg_kscrashsentry_resumeThreads(); - abort(); - } else { - bsg_kscrashsentry_resumeThreads(); - } - pthread_mutex_unlock(&bsg_suspend_threads_mutex); -} diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.h deleted file mode 100644 index bae219908..000000000 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.h +++ /dev/null @@ -1,89 +0,0 @@ -// -// BSG_KSCrashSentry_User.h -// -// Copyright (c) 2012 Karl Stenerud. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall remain in place -// in this source code. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#ifndef HDR_BSG_KSCrashSentry_User_h -#define HDR_BSG_KSCrashSentry_User_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include "BSG_KSCrashSentry.h" - -#include -#include - -/** Install the user exception handler. - * - * @param context Contextual information for the crash handler. - * - * @return true if installation was succesful. - */ -bool bsg_kscrashsentry_installUserExceptionHandler( - BSG_KSCrash_SentryContext *context); - -/** Uninstall the user exception handler. - */ -void bsg_kscrashsentry_uninstallUserExceptionHandler(void); - -/** Report a custom, user defined exception. - * If terminateProgram is true, all sentries will be uninstalled and the - * application will terminate with an abort(). - * - * @param name The exception name (for namespacing exception types). - * - * @param reason A description of why the exception occurred. - * @param handledState The severity, reason, and handled-ness of the report - * @param appState breadcrumbs and other app environmental info - * @param overrides Report fields overridden by callbacks, collated in the - * final report - * @param metadata additional information to attach to the report - * - */ -void bsg_kscrashsentry_reportUserException(const char *name, const char *reason, - const char *severity, - const char *handledState, - const char *overrides, - const char *eventOverrides, - const char *metadata, - const char *appState, - const char *config); - -/** - * Suspends execution of all threads, which is required to collect an - * accurate error report. If threads are already frozen calling this has no effect. - */ -void bsg_kscrashsentry_suspend_threads_user(void); - -/** - * Resumes execution of all threads, which is required after collecting an - * error report. If threads are already resumed calling this has no effect. - */ -void bsg_kscrashsentry_resume_threads_user(bool terminateProgram); - -#ifdef __cplusplus -} -#endif - -#endif // HDR_KSCrashSentry_User_h diff --git a/Bugsnag/Payload/BugsnagThread+Recording.m b/Bugsnag/Payload/BugsnagThread+Recording.m index e6b51484f..3fb1494b0 100644 --- a/Bugsnag/Payload/BugsnagThread+Recording.m +++ b/Bugsnag/Payload/BugsnagThread+Recording.m @@ -12,9 +12,23 @@ #import "BugsnagThread+Private.h" #include "BSG_KSBacktrace_Private.h" -#include "BSG_KSCrashSentry_User.h" +#include "BSG_KSCrashSentry_Private.h" #include "BSG_KSMach.h" +#include + +// Protect access to thread-unsafe bsg_kscrashsentry_suspendThreads() +static pthread_mutex_t bsg_suspend_threads_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void suspend_threads() { + pthread_mutex_lock(&bsg_suspend_threads_mutex); + bsg_kscrashsentry_suspendThreads(); +} + +static void resume_threads() { + bsg_kscrashsentry_resumeThreads(); + pthread_mutex_unlock(&bsg_suspend_threads_mutex); +} #define kMaxAddresses 150 // same as BSG_kMaxBacktraceDepth @@ -54,14 +68,14 @@ @implementation BugsnagThread (Recording) thread_t *threads = NULL; mach_msg_type_number_t threadCount = 0; - bsg_kscrashsentry_suspend_threads_user(); + suspend_threads(); // While threads are suspended only async-signal-safe functions should be used, // as another threads may have been suspended while holding a lock in malloc, // the Objective-C runtime, or other subsystems. if (task_threads(mach_task_self(), &threads, &threadCount) != KERN_SUCCESS) { - bsg_kscrashsentry_resume_threads_user(false); + resume_threads(); return @[]; } @@ -76,7 +90,7 @@ @implementation BugsnagThread (Recording) } } - bsg_kscrashsentry_resume_threads_user(false); + resume_threads(); NSMutableArray *objects = [NSMutableArray arrayWithCapacity:threadCount]; diff --git a/Tests/BugsnagConfigurationTests.m b/Tests/BugsnagConfigurationTests.m index 72dedc144..26fe90392 100644 --- a/Tests/BugsnagConfigurationTests.m +++ b/Tests/BugsnagConfigurationTests.m @@ -765,10 +765,6 @@ -(void)testCrashTypeMapping { XCTAssertEqual(crashTypes, [sentry mapKSToBSGCrashTypes:[config enabledErrorTypes]]); - crashTypes = crashTypes | BSG_KSCrashTypeUserReported; - - XCTAssertNotEqual(crashTypes, [sentry mapKSToBSGCrashTypes:[config enabledErrorTypes]]); - // Check partial sets BugsnagErrorTypes *errorTypes = [BugsnagErrorTypes new]; errorTypes.ooms = false; diff --git a/Tests/KSCrash/KSCrashState_Tests.m b/Tests/KSCrash/KSCrashState_Tests.m index 2b9930ce2..9b1834686 100755 --- a/Tests/KSCrash/KSCrashState_Tests.m +++ b/Tests/KSCrash/KSCrashState_Tests.m @@ -135,19 +135,6 @@ - (void) testInitCrash XCTAssertTrue(context.crashedLastLaunch, @""); } -- (void)testCrashThisLaunchWithUserReported -{ - BSG_KSCrash_State context = {0}; - NSString* stateFile = [self.tempPath stringByAppendingPathComponent:@"state.json"]; - - bsg_kscrashstate_init([stateFile cStringUsingEncoding:NSUTF8StringEncoding], - &context); - bsg_kscrashstate_notifyAppCrash(BSG_KSCrashTypeUserReported); - XCTAssertFalse(context.crashedThisLaunch, @""); - bsg_kscrashstate_notifyAppCrash(BSG_KSCrashTypeSignal); - XCTAssertTrue(context.crashedThisLaunch, @""); -} - - (void)testCrashThisLaunch { BSG_KSCrash_State context = {0}; From a50a31fa7a74bfb02e81c7413259cc2b38844bca Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 17 Mar 2021 17:10:49 +0000 Subject: [PATCH 03/20] Drop events to avoid consuming too much memory --- Bugsnag/Delivery/BSGEventUploader.m | 5 +++++ .../macos-stress-test/BugsnagStressTest/main.m | 12 +++++++++--- features/fixtures/macos-stress-test/Makefile | 3 +-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Bugsnag/Delivery/BSGEventUploader.m b/Bugsnag/Delivery/BSGEventUploader.m index a174d2b93..7d5ff1cdc 100644 --- a/Bugsnag/Delivery/BSGEventUploader.m +++ b/Bugsnag/Delivery/BSGEventUploader.m @@ -61,6 +61,11 @@ - (void)dealloc { // MARK: - Public API - (void)uploadEvent:(BugsnagEvent *)event completionHandler:(nullable void (^)(void))completionHandler { + NSUInteger operationCount = self.uploadQueue.operationCount; + if (operationCount >= self.configuration.maxPersistedEvents) { + bsg_log_warn(@"Dropping notification, %lu outstanding requests", (unsigned long)operationCount); + return; + } BSGEventUploadObjectOperation *operation = [[BSGEventUploadObjectOperation alloc] initWithEvent:event delegate:self]; operation.completionBlock = completionHandler; [self.uploadQueue addOperation:operation]; diff --git a/features/fixtures/macos-stress-test/BugsnagStressTest/main.m b/features/fixtures/macos-stress-test/BugsnagStressTest/main.m index e88f083b6..c94b06a7f 100644 --- a/features/fixtures/macos-stress-test/BugsnagStressTest/main.m +++ b/features/fixtures/macos-stress-test/BugsnagStressTest/main.m @@ -17,8 +17,8 @@ static const NSInteger kMaxConcurrentNotifies = 8; -// Note: memory usage increases with the number of threads -static const mach_vm_size_t kMemoryLimit = 50 * 1024 * 1024; +// Note: memory usage increases in line with the number of threads and config.maxPersistedEvents +static const mach_vm_size_t kMemoryLimit = 45 * 1024 * 1024; int main(int argc, const char * argv[]) { if (getenv("QUIET")) { @@ -32,6 +32,12 @@ int main(int argc, const char * argv[]) { notifyQueue.maxConcurrentOperationCount = kMaxConcurrentNotifies; @autoreleasepool { + [NSFileManager.defaultManager removeItemAtURL: + [[NSFileManager.defaultManager + URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask + appropriateForURL:nil create:NO error:nil] + URLByAppendingPathComponent:@"com.bugsnag.Bugsnag"] error:nil]; + BugsnagConfiguration *config = [BugsnagConfiguration loadConfig]; config.apiKey = @"0192837465afbecd0192837465afbecd"; config.autoDetectErrors = NO; @@ -81,7 +87,7 @@ int main(int argc, const char * argv[]) { maxFootprint = MAX(maxFootprint, task_vm_info.phys_footprint); if (task_vm_info.phys_footprint > kMemoryLimit) { NSLog(@"💥 Memory limit (%d MB) exceeded", (int)kMemoryLimit / (1024 * 1024)); - return 1; + abort(); } } diff --git a/features/fixtures/macos-stress-test/Makefile b/features/fixtures/macos-stress-test/Makefile index 3c6ad61c0..927e03959 100644 --- a/features/fixtures/macos-stress-test/Makefile +++ b/features/fixtures/macos-stress-test/Makefile @@ -16,7 +16,6 @@ clean: rm -rf build Pods *.log run: - rm -rf $(HOME)/Library/Application\ Support/com.bugsnag.Bugsnag QUIET=true /usr/bin/time -l ./build/usr/local/bin/BugsnagStressTest rm -rf $(HOME)/Library/Application\ Support/com.bugsnag.Bugsnag - echo "macOS stress-test complete" + @echo "macOS stress-test complete" From beb0d5ef7a193ecad89d4794c00b9ada78934b2c Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Thu, 18 Mar 2021 15:00:33 +0000 Subject: [PATCH 04/20] Fix -[BugsnagEvent attachCustomStacktrace:withType:] --- Bugsnag.xcodeproj/project.pbxproj | 6 ++- Bugsnag/Payload/BugsnagError+Private.h | 3 ++ Bugsnag/Payload/BugsnagError.m | 44 +++++++++++++------ Bugsnag/Payload/BugsnagEvent+Private.h | 7 +-- Bugsnag/Payload/BugsnagEvent.m | 47 ++------------------- Bugsnag/Payload/BugsnagStackframe.m | 23 ++++++++++ Bugsnag/Payload/BugsnagStacktrace+Private.h | 21 --------- Bugsnag/Payload/BugsnagStacktrace.h | 4 ++ Bugsnag/Payload/BugsnagStacktrace.m | 4 +- Bugsnag/Payload/BugsnagThread.m | 2 +- Bugsnag/include/Bugsnag/BugsnagError.h | 2 +- Tests/BugsnagStacktraceTest.m | 14 +++++- 12 files changed, 87 insertions(+), 90 deletions(-) delete mode 100644 Bugsnag/Payload/BugsnagStacktrace+Private.h diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index 092e13196..fb0b930b1 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -1297,7 +1297,6 @@ 0126DEE7257A8B0F0031A70C /* BugsnagDevice+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagDevice+Private.h"; sourceTree = ""; }; 0126DEEF257A8C3D0031A70C /* BugsnagDeviceWithState+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagDeviceWithState+Private.h"; sourceTree = ""; }; 0126DF1A257A92860031A70C /* BugsnagSession+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "BugsnagSession+Private.h"; sourceTree = ""; }; - 0126DF2C257A92D70031A70C /* BugsnagStacktrace+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagStacktrace+Private.h"; sourceTree = ""; }; 0126DF34257A94740031A70C /* BugsnagUser+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagUser+Private.h"; sourceTree = ""; }; 0126F78925DD508C008483C2 /* BSGEventUploadOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGEventUploadOperation.h; sourceTree = ""; }; 0126F78A25DD508C008483C2 /* BSGEventUploadOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGEventUploadOperation.m; sourceTree = ""; }; @@ -1890,7 +1889,6 @@ 0198762E2567D5AB000A7AF3 /* BugsnagStackframe+Private.h */, 0089684F2486DA9400DC48C2 /* BugsnagStacktrace.h */, 0089685C2486DA9500DC48C2 /* BugsnagStacktrace.m */, - 0126DF2C257A92D70031A70C /* BugsnagStacktrace+Private.h */, 008968552486DA9400DC48C2 /* BugsnagStateEvent.h */, 008968582486DA9500DC48C2 /* BugsnagStateEvent.m */, 008968612486DA9500DC48C2 /* BugsnagThread.m */, @@ -3225,6 +3223,7 @@ "DEBUG=1", "$(inherited)", ); + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -3247,6 +3246,7 @@ SDKROOT = iphoneos; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WARNING_CFLAGS = "-Werror=incomplete-implementation"; }; name = Debug; }; @@ -3292,6 +3292,7 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -3314,6 +3315,7 @@ VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; + WARNING_CFLAGS = "-Werror=incomplete-implementation"; }; name = Release; }; diff --git a/Bugsnag/Payload/BugsnagError+Private.h b/Bugsnag/Payload/BugsnagError+Private.h index 99308add9..af5ef98cc 100644 --- a/Bugsnag/Payload/BugsnagError+Private.h +++ b/Bugsnag/Payload/BugsnagError+Private.h @@ -23,6 +23,9 @@ NS_ASSUME_NONNULL_BEGIN + (BugsnagError *)errorFromJson:(NSDictionary *)json; +/// The string representation of the BSGErrorType +@property (copy, nonatomic) NSString *typeString; + /// Parses the `__crash_info` message and updates the `errorClass` and `errorMessage` as appropriate. - (void)updateWithCrashInfoMessage:(NSString *)crashInfoMessage; diff --git a/Bugsnag/Payload/BugsnagError.m b/Bugsnag/Payload/BugsnagError.m index b4f96f886..606fb3de1 100644 --- a/Bugsnag/Payload/BugsnagError.m +++ b/Bugsnag/Payload/BugsnagError.m @@ -17,23 +17,30 @@ #import "BugsnagThread+Private.h" +typedef NSString * BSGErrorTypeString NS_TYPED_ENUM; + +BSGErrorTypeString const BSGErrorTypeStringCocoa = @"cocoa"; +BSGErrorTypeString const BSGErrorTypeStringC = @"c"; +BSGErrorTypeString const BSGErrorTypeStringReactNativeJs = @"reactnativejs"; + + NSString *_Nonnull BSGSerializeErrorType(BSGErrorType errorType) { switch (errorType) { case BSGErrorTypeCocoa: - return @"cocoa"; + return BSGErrorTypeStringCocoa; case BSGErrorTypeC: - return @"c"; + return BSGErrorTypeStringC; case BSGErrorTypeReactNativeJs: - return @"reactnativejs"; + return BSGErrorTypeStringReactNativeJs; } } BSGErrorType BSGParseErrorType(NSString *errorType) { - if ([@"cocoa" isEqualToString:errorType]) { + if ([BSGErrorTypeStringCocoa isEqualToString:errorType]) { return BSGErrorTypeCocoa; - } else if ([@"c" isEqualToString:errorType]) { + } else if ([BSGErrorTypeStringC isEqualToString:errorType]) { return BSGErrorTypeC; - } else if ([@"reactnativejs" isEqualToString:errorType]) { + } else if ([BSGErrorTypeStringReactNativeJs isEqualToString:errorType]) { return BSGErrorTypeReactNativeJs; } else { return BSGErrorTypeCocoa; @@ -74,6 +81,8 @@ BSGErrorType BSGParseErrorType(NSString *errorType) { @implementation BugsnagError +@dynamic type; + - (instancetype)initWithErrorReportingThread:(BugsnagThread *)thread { return [self initWithEvent:@{} errorReportingThread:thread]; } @@ -84,7 +93,7 @@ - (instancetype)initWithEvent:(NSDictionary *)event errorReportingThread:(Bugsna NSString *errorType = error[BSGKeyType]; _errorClass = BSGParseErrorClass(error, errorType); _errorMessage = BSGParseErrorMessage(event, error, errorType); - _type = BSGErrorTypeCocoa; + _typeString = BSGSerializeErrorType(BSGErrorTypeCocoa); if (![[event valueForKeyPath:@"user.state.didOOM"] boolValue]) { _stacktrace = thread.stacktrace; @@ -100,7 +109,7 @@ - (instancetype)initWithErrorClass:(NSString *)errorClass if (self = [super init]) { _errorClass = errorClass; _errorMessage = errorMessage; - _type = errorType; + _typeString = BSGSerializeErrorType(errorType); _stacktrace = stacktrace; } return self; @@ -119,13 +128,22 @@ + (BugsnagError *)errorFromJson:(NSDictionary *)json { } } } - BugsnagError *error = [[BugsnagError alloc] initWithErrorClass:json[BSGKeyErrorClass] - errorMessage:json[BSGKeyMessage] - errorType:BSGParseErrorType(json[BSGKeyType]) - stacktrace:data]; + BugsnagError *error = [[BugsnagError alloc] init]; + error.errorClass = json[BSGKeyErrorClass]; + error.errorMessage = json[BSGKeyMessage]; + error.stacktrace = data; + error.typeString = json[BSGKeyType]; return error; } +- (BSGErrorType)type { + return BSGParseErrorType(self.typeString); +} + +- (void)setType:(BSGErrorType)type { + self.typeString = BSGSerializeErrorType(type); +} + - (void)updateWithCrashInfoMessage:(NSString *)crashInfoMessage { NSArray *patterns = @[ // From Swift 2.2: https://github.com/apple/swift/blob/swift-2.2-RELEASE/stdlib/public/stubs/Assert.cpp#L24-L39 @@ -179,7 +197,7 @@ - (NSDictionary *)toDictionary { NSMutableDictionary *dict = [NSMutableDictionary new]; dict[BSGKeyErrorClass] = self.errorClass; dict[BSGKeyMessage] = self.errorMessage; - dict[BSGKeyType] = BSGSerializeErrorType(self.type); + dict[BSGKeyType] = self.typeString; NSMutableArray *frames = [NSMutableArray new]; for (BugsnagStackframe *frame in self.stacktrace) { diff --git a/Bugsnag/Payload/BugsnagEvent+Private.h b/Bugsnag/Payload/BugsnagEvent+Private.h index 0e56502b0..e92227794 100644 --- a/Bugsnag/Payload/BugsnagEvent+Private.h +++ b/Bugsnag/Payload/BugsnagEvent+Private.h @@ -34,11 +34,8 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, nonatomic) BugsnagMetadata *metadata; -/// Property overrides. -@property (readonly, nonatomic) NSDictionary *overrides; - /// The release stage of the application -@property (readwrite, copy, nullable) NSString *releaseStage; +@property (readwrite, copy, nullable, nonatomic) NSString *releaseStage; @property (strong, nullable, nonatomic) BugsnagSession *session; @@ -68,8 +65,6 @@ NS_ASSUME_NONNULL_BEGIN /// Whether this report should be sent, based on release stage information cached at crash time and within the application currently. - (BOOL)shouldBeSent; -- (void)setOverrideProperty:(NSString *)key value:(id)value; - - (NSDictionary *)toJsonWithRedactedKeys:(nullable NSSet *)redactedKeys; - (void)notifyUnhandledOverridden; diff --git a/Bugsnag/Payload/BugsnagEvent.m b/Bugsnag/Payload/BugsnagEvent.m index b05553ab0..3335d4dc8 100644 --- a/Bugsnag/Payload/BugsnagEvent.m +++ b/Bugsnag/Payload/BugsnagEvent.m @@ -34,7 +34,7 @@ #import "BugsnagMetadata+Private.h" #import "BugsnagLogger.h" #import "BugsnagSession+Private.h" -#import "BugsnagStacktrace+Private.h" +#import "BugsnagStacktrace.h" #import "BugsnagThread+Private.h" #import "BugsnagUser+Private.h" @@ -340,7 +340,6 @@ - (instancetype)initWithKSCrashData:(NSDictionary *)event { session:session]; obj.context = BSGParseContext(event); obj.groupingHash = BSGParseGroupingHash(event); - obj.overrides = [event valueForKeyPath:@"user.overrides"]; obj.enabledReleaseStages = BSGLoadConfigValue(event, BSGKeyEnabledReleaseStages); obj.releaseStage = BSGParseReleaseStage(event); obj.deviceAppHash = deviceAppHash; @@ -467,24 +466,10 @@ - (NSArray *)serializeBreadcrumbs { return [[self breadcrumbs] valueForKeyPath:NSStringFromSelector(@selector(objectValue))]; } -@synthesize releaseStage = _releaseStage; - -- (NSString *)releaseStage { - @synchronized (self) { - return _releaseStage; - } -} - -- (void)setReleaseStage:(NSString *)releaseStage { - [self setOverrideProperty:BSGKeyReleaseStage value:releaseStage]; - @synchronized (self) { - _releaseStage = releaseStage; - } -} - - (void)attachCustomStacktrace:(NSArray *)frames withType:(NSString *)type { - [self setOverrideProperty:@"customStacktraceFrames" value:frames]; - [self setOverrideProperty:@"customStacktraceType" value:type]; + BugsnagError *error = self.errors.firstObject; + error.stacktrace = [BugsnagStacktrace stacktraceFromJson:frames].trace; + error.typeString = type; } - (BSGSeverity)severity { @@ -549,30 +534,6 @@ - (BugsnagUser *)parseUser:(NSDictionary *)event // MARK: - Callback overrides -@synthesize overrides = _overrides; - -- (NSDictionary *)overrides { - NSMutableDictionary *values = [_overrides mutableCopy] ?: [NSMutableDictionary new]; - values[BSGKeyBreadcrumbs] = [self serializeBreadcrumbs]; - return values; -} - -- (void)setOverrides:(NSDictionary * _Nonnull)overrides { - _overrides = overrides; -} - -- (void)setOverrideProperty:(NSString *)key value:(id)value { - @synchronized (self) { - NSMutableDictionary *metadata = [self.overrides mutableCopy]; - if (value) { - metadata[key] = value; - } else { - [metadata removeObjectForKey:key]; - } - self.overrides = metadata; - } -} - - (void)notifyUnhandledOverridden { self.handledState.unhandledOverridden = YES; } diff --git a/Bugsnag/Payload/BugsnagStackframe.m b/Bugsnag/Payload/BugsnagStackframe.m index a3964348d..7dfde07e7 100644 --- a/Bugsnag/Payload/BugsnagStackframe.m +++ b/Bugsnag/Payload/BugsnagStackframe.m @@ -16,6 +16,21 @@ BugsnagStackframeType const BugsnagStackframeTypeCocoa = @"cocoa"; + +// MARK: - Properties not used for Cocoa stack frames, but used by React Native and Unity. + +@interface BugsnagStackframe () + +@property (strong, nullable, nonatomic) NSNumber *columnNumber; +@property (copy, nullable, nonatomic) NSString *file; +@property (strong, nullable, nonatomic) NSNumber *inProject; +@property (strong, nullable, nonatomic) NSNumber *lineNumber; + +@end + + +// MARK: - + @implementation BugsnagStackframe + (NSDictionary *_Nullable)findImageAddr:(unsigned long)addr inImages:(NSArray *)images { @@ -39,6 +54,10 @@ + (BugsnagStackframe *)frameFromJson:(NSDictionary *)json { frame.symbolAddress = [self readInt:json key:BSGKeySymbolAddr]; frame.machoLoadAddress = [self readInt:json key:BSGKeyMachoLoadAddr]; frame.type = json[BSGKeyType]; + frame.columnNumber = json[@"columnNumber"]; + frame.file = json[@"file"]; + frame.inProject = json[@"inProject"]; + frame.lineNumber = json[@"lineNumber"]; return frame; } @@ -231,6 +250,10 @@ - (NSDictionary *)toDictionary { dict[BSGKeyIsLR] = @(self.isLr); } dict[BSGKeyType] = self.type; + dict[@"columnNumber"] = self.columnNumber; + dict[@"file"] = self.file; + dict[@"inProject"] = self.inProject; + dict[@"lineNumber"] = self.lineNumber; return dict; } diff --git a/Bugsnag/Payload/BugsnagStacktrace+Private.h b/Bugsnag/Payload/BugsnagStacktrace+Private.h deleted file mode 100644 index b8b2bf361..000000000 --- a/Bugsnag/Payload/BugsnagStacktrace+Private.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// BugsnagStacktrace+Private.h -// Bugsnag -// -// Created by Nick Dowell on 04/12/2020. -// Copyright © 2020 Bugsnag Inc. All rights reserved. -// - -#import "BugsnagStacktrace.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface BugsnagStacktrace () - -+ (instancetype)stacktraceFromJson:(NSDictionary *)json; - -@property (nonatomic) NSMutableArray *trace; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Bugsnag/Payload/BugsnagStacktrace.h b/Bugsnag/Payload/BugsnagStacktrace.h index d789498a1..cf97afd5e 100644 --- a/Bugsnag/Payload/BugsnagStacktrace.h +++ b/Bugsnag/Payload/BugsnagStacktrace.h @@ -18,6 +18,10 @@ - (instancetype)initWithTrace:(NSArray *)trace binaryImages:(NSArray *)binaryImages; ++ (instancetype)stacktraceFromJson:(NSArray *)json; + +@property (nonatomic) NSMutableArray *trace; + - (NSArray *)toArray; @end diff --git a/Bugsnag/Payload/BugsnagStacktrace.m b/Bugsnag/Payload/BugsnagStacktrace.m index d17969e6c..7c9d37c49 100644 --- a/Bugsnag/Payload/BugsnagStacktrace.m +++ b/Bugsnag/Payload/BugsnagStacktrace.m @@ -6,14 +6,14 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import "BugsnagStacktrace+Private.h" +#import "BugsnagStacktrace.h" #import "BugsnagKeys.h" #import "BugsnagStackframe+Private.h" @implementation BugsnagStacktrace -+ (instancetype)stacktraceFromJson:(NSDictionary *)json { ++ (instancetype)stacktraceFromJson:(NSArray *)json { BugsnagStacktrace *trace = [BugsnagStacktrace new]; NSMutableArray *data = [NSMutableArray new]; diff --git a/Bugsnag/Payload/BugsnagThread.m b/Bugsnag/Payload/BugsnagThread.m index 981902fb1..253035ff4 100644 --- a/Bugsnag/Payload/BugsnagThread.m +++ b/Bugsnag/Payload/BugsnagThread.m @@ -11,7 +11,7 @@ #import "BSG_KSCrashReportFields.h" #import "BugsnagCollections.h" #import "BugsnagStackframe+Private.h" -#import "BugsnagStacktrace+Private.h" +#import "BugsnagStacktrace.h" #import "BugsnagKeys.h" BSGThreadType BSGParseThreadType(NSString *type) { diff --git a/Bugsnag/include/Bugsnag/BugsnagError.h b/Bugsnag/include/Bugsnag/BugsnagError.h index 4efa76cbd..fcaa821ce 100644 --- a/Bugsnag/include/Bugsnag/BugsnagError.h +++ b/Bugsnag/include/Bugsnag/BugsnagError.h @@ -42,6 +42,6 @@ typedef NS_OPTIONS(NSUInteger, BSGErrorType) { /** * The type of the captured error */ -@property BSGErrorType type; +@property (nonatomic) BSGErrorType type; @end diff --git a/Tests/BugsnagStacktraceTest.m b/Tests/BugsnagStacktraceTest.m index 99b602c5a..c7f9440c5 100644 --- a/Tests/BugsnagStacktraceTest.m +++ b/Tests/BugsnagStacktraceTest.m @@ -8,7 +8,7 @@ #import -#import "BugsnagStacktrace+Private.h" +#import "BugsnagStacktrace.h" @interface BugsnagStacktraceTest : XCTestCase @property NSDictionary *frameDict; @@ -50,4 +50,16 @@ - (void)testLongTraceTrimmed { XCTAssertEqual(200, [stacktrace.trace count]); } +- (void)testNonCocoaJson { + NSArray *json = @[ + @{@"method": @"foo()", @"file": @"src/Giraffe.mm", @"lineNumber": @200, @"columnNumber": @42, @"inProject": @YES}, + @{@"method": @"foo()", @"file": @"src/Giraffe.mm", @"lineNumber": @200, @"columnNumber": @42}, + @{@"method": @"foo()", @"file": @"src/Giraffe.mm", @"lineNumber": @200}, + @{@"method": @"bar()", @"file": @"parser.js"}, + @{@"method": @"yes()"} + ]; + BugsnagStacktrace *stacktrace = [BugsnagStacktrace stacktraceFromJson:json]; + XCTAssertEqualObjects([stacktrace toArray], json); +} + @end From 3d0a514e128ba5a4dd559e99e520ee634fae9b5e Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 19 Mar 2021 11:38:49 +0000 Subject: [PATCH 05/20] Fix E2E failures due to crashes before delivery --- .../AutoSessionMixedEventsScenario.m | 18 ----- .../scenarios/EnabledErrorTypesCxxScenario.mm | 4 +- .../scenarios/EnabledErrorTypesScenario.m | 12 ++- features/fixtures/shared/scenarios/Scenario.h | 2 +- features/fixtures/shared/scenarios/Scenario.m | 80 +++++++++---------- 5 files changed, 51 insertions(+), 65 deletions(-) diff --git a/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m b/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m index d9d2e3960..3844b1e27 100644 --- a/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m +++ b/features/fixtures/shared/scenarios/AutoSessionMixedEventsScenario.m @@ -22,15 +22,6 @@ @implementation SecondErr @implementation AutoSessionMixedEventsScenario -- (void)startBugsnag { - self.config.session = [self URLSessionWithObserver:^(NSURLRequest *request, NSData *responseData, NSURLResponse *response, NSError *error) { - if (self.onEventDelivery && [request.URL.absoluteString isEqual:self.config.endpoints.notify]) { - self.onEventDelivery(); - } - }]; - [super startBugsnag]; -} - - (void)run { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self performBlockAndWaitForEventDelivery:^{ @@ -43,13 +34,4 @@ - (void)run { }); } -- (void)performBlockAndWaitForEventDelivery:(dispatch_block_t)block { - NSCondition *condition = [[NSCondition alloc] init]; - self.onEventDelivery = ^{ - [condition signal]; - }; - block(); - [condition wait]; -} - @end diff --git a/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm b/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm index a1d1ce7b7..8592bb656 100644 --- a/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm +++ b/features/fixtures/shared/scenarios/EnabledErrorTypesCxxScenario.mm @@ -34,7 +34,9 @@ - (void)run { - (void)crash __attribute__((noreturn)) { // Notify error so that mazerunner sees something - [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + [self performBlockAndWaitForEventDelivery:^{ + [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + }]; throw new disabled_cxx_reporting_kaboom_exception; } diff --git a/features/fixtures/shared/scenarios/EnabledErrorTypesScenario.m b/features/fixtures/shared/scenarios/EnabledErrorTypesScenario.m index af4b27550..fd140f9d1 100644 --- a/features/fixtures/shared/scenarios/EnabledErrorTypesScenario.m +++ b/features/fixtures/shared/scenarios/EnabledErrorTypesScenario.m @@ -32,7 +32,9 @@ - (void)startBugsnag { - (void)run { // Notify error so that mazerunner sees something - [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + [self performBlockAndWaitForEventDelivery:^{ + [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + }]; // From null prt scenario volatile char *ptr = NULL; @@ -86,7 +88,9 @@ - (void)startBugsnag { #pragma clang diagnostic ignored "-Winvalid-noreturn" - (void)run __attribute__((noreturn)) { // Notify error so that mazerunner sees something - [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + [self performBlockAndWaitForEventDelivery:^{ + [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + }]; strcmp(0, ""); // Generate EXC_BAD_ACCESS (see e.g. https://stackoverflow.com/q/22488358/2431627) } @@ -111,7 +115,9 @@ - (void)startBugsnag { #pragma clang diagnostic ignored "-Winvalid-noreturn" - (void)run __attribute__((noreturn)) { // Notify error so that mazerunner sees something - [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + [self performBlockAndWaitForEventDelivery:^{ + [Bugsnag notifyError:[NSError errorWithDomain:@"com.bugsnag" code:833 userInfo:nil]]; + }]; raise(SIGINT); } diff --git a/features/fixtures/shared/scenarios/Scenario.h b/features/fixtures/shared/scenarios/Scenario.h index 8aa06f43d..473619c16 100644 --- a/features/fixtures/shared/scenarios/Scenario.h +++ b/features/fixtures/shared/scenarios/Scenario.h @@ -34,7 +34,7 @@ void markErrorHandledCallback(const BSG_KSCrashReportWriter *writer); @property (nonatomic, strong, nullable) NSString *eventMode; -- (NSURLSession *)URLSessionWithObserver:(void (^)(NSURLRequest *request, NSData *responseData, NSURLResponse *response, NSError *error))observer; +- (void)performBlockAndWaitForEventDelivery:(dispatch_block_t)block NS_SWIFT_NAME(performBlockAndWaitForEventDelivery(_:)); @end diff --git a/features/fixtures/shared/scenarios/Scenario.m b/features/fixtures/shared/scenarios/Scenario.m index a64eb3120..8680e0963 100644 --- a/features/fixtures/shared/scenarios/Scenario.m +++ b/features/fixtures/shared/scenarios/Scenario.m @@ -12,20 +12,11 @@ void markErrorHandledCallback(const BSG_KSCrashReportWriter *writer) { // MARK: - -typedef void (^ URLSessionResponseObserver)(NSURLRequest *request, NSData *responseData, NSURLResponse *response, NSError *error); +static Scenario *theScenario; -@interface ObservableURLSession : NSObject - -+ (instancetype)sessionWithObserver:(URLSessionResponseObserver)observer; - -@property (copy, nonatomic) URLSessionResponseObserver observer; - -@end - - -// MARK: - - -@implementation Scenario +@implementation Scenario { + dispatch_block_t _onEventDelivery; +} + (Scenario *)createScenarioNamed:(NSString *)className withConfig:(BugsnagConfiguration *)config { @@ -61,6 +52,8 @@ + (Scenario *)createScenarioNamed:(NSString *)className NSAssert([obj isKindOfClass:[Scenario class]], @"Class '%@' is not a subclass of Scenario", className); + theScenario = obj; + return [(Scenario *)obj initWithConfig:config]; } @@ -110,39 +103,42 @@ - (void)startBugsnag { - (void)didEnterBackgroundNotification { } -- (NSURLSession *)URLSessionWithObserver:(URLSessionResponseObserver)observer { - return (id)[ObservableURLSession sessionWithObserver:observer]; -} - -@end - - -// MARK: - - -@implementation ObservableURLSession - -// NSURLSession does not allow subclassing - calling [ObservableURLSession sessionWithConfiguration:] will return an -// instance of NSURLSession instead of ObservableURLSession, so we have to resort to acting as a proxy object. - -+ (instancetype)sessionWithObserver:(URLSessionResponseObserver)observer { - ObservableURLSession *session = [[ObservableURLSession alloc] init]; - session.observer = observer; - return session; +- (void)performBlockAndWaitForEventDelivery:(dispatch_block_t)block { + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + _onEventDelivery = ^{ + dispatch_semaphore_signal(semaphore); + }; + block(); + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); } -- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData - completionHandler:(void (^)(NSData *, NSURLResponse *, NSError *))completionHandler { - return [NSURLSession.sharedSession uploadTaskWithRequest:request fromData:bodyData completionHandler: - ^(NSData *responseData, NSURLResponse *response, NSError *error) { - completionHandler(responseData, response, error); - if (self.observer) { - self.observer(request, responseData, response, error); - } - }]; +- (void)requestDidComplete:(NSURLRequest *)request { + if (_onEventDelivery && [request.URL.absoluteString isEqual:self.config.endpoints.notify]) { + _onEventDelivery(); + _onEventDelivery = nil; + } } -- (id)forwardingTargetForSelector:(SEL)aSelector { - return NSURLSession.sharedSession; +// Pointer to the original implementation of -[NSURLSession uploadTaskWithRequest:fromData:completionHandler:] +static NSURLSessionUploadTask * (* NSURLSession_uploadTaskWithRequest_fromData_completionHandler) + (NSURLSession *session, SEL _cmd, NSURLRequest *request, NSData *fromData, void (^ completionHandler)(NSData *, NSURLResponse *, NSError *)); + +// Custom implmentation of -[NSURLSession uploadTaskWithRequest:fromData:completionHandler:] to allow tracking when requests finish +static NSURLSessionUploadTask * uploadTaskWithRequest_fromData_completionHandler + (NSURLSession *session, SEL _cmd, NSURLRequest *request, NSData *fromData, void (^ completionHandler)(NSData *, NSURLResponse *, NSError *)) { + return NSURLSession_uploadTaskWithRequest_fromData_completionHandler(session, _cmd, request, fromData, + ^(NSData *responseData, NSURLResponse *response, NSError *error) { + completionHandler(responseData, response, error); + [theScenario requestDidComplete:request]; + }); + } + ++ (void)initialize { + if (self == [Scenario self]) { + Method method = class_getInstanceMethod([NSURLSession class], @selector(uploadTaskWithRequest:fromData:completionHandler:)); + NSURLSession_uploadTaskWithRequest_fromData_completionHandler = + (void *)method_setImplementation(method, (void *)uploadTaskWithRequest_fromData_completionHandler); + } } @end From b5801f5a70a595334452fd4d7a1d624d6b1c9d3d Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 19 Mar 2021 12:50:35 +0000 Subject: [PATCH 06/20] Disable macOS Crash Reporter alerts to prevent flakes --- features/support/env.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/support/env.rb b/features/support/env.rb index 973f3107e..0b3d6a965 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -17,6 +17,10 @@ # Additional require MacOS configuration if Maze.config.os == 'macos' + # The default macOS Crash Reporter "#{app_name} quit unexpectedly" alert grabs focus which can cause tests to flake. + # This option, which appears to have been introduced in macOS 10.11, displays a notification instead of the alert. + `defaults write com.apple.CrashReporter UseUNC 1` + fixture_dir = 'features/fixtures/macos/output' app_dir = '/Applications' zip_name = "#{Maze.config.app}.zip" From 586c572e7e938e7083ea5d271e454060c404a743 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 19 Mar 2021 14:59:48 +0000 Subject: [PATCH 07/20] Store unhandled errors to disk (for React Native) --- Bugsnag/Client/BugsnagClient.m | 13 ++++++++++++- Bugsnag/Delivery/BSGEventUploadObjectOperation.m | 11 ++--------- Bugsnag/Delivery/BSGEventUploadOperation.h | 8 +++----- Bugsnag/Delivery/BSGEventUploadOperation.m | 7 +++---- Bugsnag/Delivery/BSGEventUploader.h | 2 ++ Bugsnag/Delivery/BSGEventUploader.m | 14 +++++++++++++- 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index de9063c16..8b5b7d4c8 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -934,7 +934,18 @@ - (void)notifyInternal:(BugsnagEvent *_Nonnull)event [self.sessionTracker handleHandledErrorEvent]; } - [self.eventUploader uploadEvent:event completionHandler:nil]; + if (event.unhandled) { + // Unhandled Javscript exceptions from React Native result in the app being terminated shortly after the + // call to notifyInternal, so the event needs to be persisted to disk for sending in the next session. + // The fatal "RCTFatalException" / "Unhandled JS Exception" is explicitly ignored by + // BugsnagReactNativePlugin's OnSendErrorBlock. + [self.eventUploader storeEvent:event]; + // Replicate previous delivery mechanism's behaviour of waiting 1 second before delivering the event. + // This should prevent potential duplicate uploads of unhandled errors where the app subsequently terminates. + [self.eventUploader performSelector:@selector(uploadStoredEvents) withObject:nil afterDelay:1]; + } else { + [self.eventUploader uploadEvent:event completionHandler:nil]; + } [self addAutoBreadcrumbForEvent:event]; } diff --git a/Bugsnag/Delivery/BSGEventUploadObjectOperation.m b/Bugsnag/Delivery/BSGEventUploadObjectOperation.m index 6ed204266..82a53bcd7 100644 --- a/Bugsnag/Delivery/BSGEventUploadObjectOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadObjectOperation.m @@ -8,7 +8,6 @@ #import "BSGEventUploadObjectOperation.h" -#import "BSGJSONSerialization.h" #import "BugsnagEvent.h" #import "BugsnagLogger.h" @@ -25,14 +24,8 @@ - (BugsnagEvent *)loadEventAndReturnError:(NSError **)errorPtr { return self.event; } -- (void)storeEventPayload:(NSDictionary *)eventPayload inDirectory:(NSString *)directory { - NSString *file = [[directory stringByAppendingPathComponent:[NSUUID UUID].UUIDString] stringByAppendingPathExtension:@"json"]; - NSError *error = nil; - if ([BSGJSONSerialization writeJSONObject:eventPayload toFile:file options:0 error:&error]) { - [self.delegate uploadOperationDidStoreEventPayload:self]; - } else { - bsg_log_err(@"Error encountered while saving event payload for retry: %@", error); - } +- (BOOL)shouldStoreEventPayloadForRetry { + return YES; } - (NSString *)name { diff --git a/Bugsnag/Delivery/BSGEventUploadOperation.h b/Bugsnag/Delivery/BSGEventUploadOperation.h index 381884956..5a4c3a4a5 100644 --- a/Bugsnag/Delivery/BSGEventUploadOperation.h +++ b/Bugsnag/Delivery/BSGEventUploadOperation.h @@ -41,10 +41,8 @@ NS_ASSUME_NONNULL_BEGIN /// To be implemented by subclasses that load their data from a file. - (void)deleteEvent; -/// Called if the event upload failed but should be retried later. -/// -/// To be implemented by subclasses that need to persist the payload for a future retry. -- (void)storeEventPayload:(NSDictionary *)eventPayload inDirectory:(NSString *)directory; +/// Whether the payload should be stored so that it can be retried later. +@property (readonly, nonatomic) BOOL shouldStoreEventPayloadForRetry; @end @@ -58,7 +56,7 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly, nonatomic) BugsnagNotifier *notifier; -- (void)uploadOperationDidStoreEventPayload:(BSGEventUploadOperation *)uploadOperation; +- (void)storeEventPayload:(NSDictionary *)eventPayload; @end diff --git a/Bugsnag/Delivery/BSGEventUploadOperation.m b/Bugsnag/Delivery/BSGEventUploadOperation.m index df8bf9733..2205ac191 100644 --- a/Bugsnag/Delivery/BSGEventUploadOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadOperation.m @@ -114,7 +114,9 @@ - (void)runWithDelegate:(id)delegate completion case BugsnagApiClientDeliveryStatusFailed: bsg_log_debug(@"Upload failed; will retry event %@", self.name); - [self storeEventPayload:eventPayload inDirectory:[BSGFileLocations current].events]; + if (self.shouldStoreEventPayloadForRetry) { + [delegate storeEventPayload:eventPayload]; + } break; case BugsnagApiClientDeliveryStatusUndeliverable: @@ -138,9 +140,6 @@ - (BugsnagEvent *)loadEventAndReturnError:(NSError **)errorPtr { - (void)deleteEvent { } -- (void)storeEventPayload:(NSDictionary *)eventPayload inDirectory:(NSString *)directory { -} - // MARK: Asynchronous NSOperation implementation - (void)start { diff --git a/Bugsnag/Delivery/BSGEventUploader.h b/Bugsnag/Delivery/BSGEventUploader.h index 67d7066a3..d6156e278 100644 --- a/Bugsnag/Delivery/BSGEventUploader.h +++ b/Bugsnag/Delivery/BSGEventUploader.h @@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration notifier:(BugsnagNotifier *)notifier; +- (void)storeEvent:(BugsnagEvent *)event; + - (void)uploadEvent:(BugsnagEvent *)event completionHandler:(nullable void (^)(void))completionHandler; - (void)uploadStoredEvents; diff --git a/Bugsnag/Delivery/BSGEventUploader.m b/Bugsnag/Delivery/BSGEventUploader.m index 7d5ff1cdc..3e3ce2141 100644 --- a/Bugsnag/Delivery/BSGEventUploader.m +++ b/Bugsnag/Delivery/BSGEventUploader.m @@ -11,7 +11,9 @@ #import "BSGEventUploadKSCrashReportOperation.h" #import "BSGEventUploadObjectOperation.h" #import "BSGFileLocations.h" +#import "BSGJSONSerialization.h" #import "BugsnagConfiguration.h" +#import "BugsnagEvent+Private.h" #import "BugsnagLogger.h" @@ -60,6 +62,10 @@ - (void)dealloc { // MARK: - Public API +- (void)storeEvent:(BugsnagEvent *)event { + [self storeEventPayload:[event toJsonWithRedactedKeys:self.configuration.redactedKeys]]; +} + - (void)uploadEvent:(BugsnagEvent *)event completionHandler:(nullable void (^)(void))completionHandler { NSUInteger operationCount = self.uploadQueue.operationCount; if (operationCount >= self.configuration.maxPersistedEvents) { @@ -175,7 +181,13 @@ - (void)deleteExcessFiles:(NSMutableArray *)sortedEventFiles { // MARK: - BSGEventUploadOperationDelegate -- (void)uploadOperationDidStoreEventPayload:(BSGEventUploadOperation *)uploadOperation { +- (void)storeEventPayload:(NSDictionary *)eventPayload { + NSString *file = [[self.eventsDirectory stringByAppendingPathComponent:[NSUUID UUID].UUIDString] stringByAppendingPathExtension:@"json"]; + NSError *error = nil; + if (![BSGJSONSerialization writeJSONObject:eventPayload toFile:file options:0 error:&error]) { + bsg_log_err(@"Error encountered while saving event payload for retry: %@", error); + return; + } [self deleteExcessFiles:[self sortedEventFiles]]; } From 36e28baac0ab6ef544524bd524bbc7479c86cab4 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 22 Mar 2021 08:59:02 +0000 Subject: [PATCH 08/20] Additional logging to help diagnose E2E failures --- Bugsnag/Client/BugsnagClient.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index 8b5b7d4c8..5dbcfba43 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -562,15 +562,18 @@ - (void)addTerminationObserver:(NSString *)name { - (void)computeDidCrashLastLaunch { // Did the app crash in a way that was detected by KSCrash? if (bsg_kscrashstate_currentState()->crashedLastLaunch || !access(crashSentinelPath, F_OK)) { + bsg_log_info(@"Last run terminated due to a crash."); unlink(crashSentinelPath); self.appDidCrashLastLaunch = YES; } // Was the app terminated while the main thread was hung? else if ((self.eventFromLastLaunch = [self loadFatalAppHangEvent])) { + bsg_log_info(@"Last run terminated during an app hang."); self.appDidCrashLastLaunch = YES; } // Was the app terminated while in the foreground? (probably an OOM) else if ([self shouldReportOOM]) { + bsg_log_info(@"Last run terminated abnormally; likely Out Of Memory."); self.eventFromLastLaunch = [self generateOutOfMemoryEvent]; self.appDidCrashLastLaunch = YES; } @@ -772,6 +775,7 @@ - (NSString *)context { // see notify:handledState:block for further info - (void)notifyError:(NSError *_Nonnull)error { + bsg_log_debug(@"Notify called with %@", error); BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledError severity:BSGSeverityWarning attrValue:error.domain]; @@ -785,6 +789,7 @@ - (void)notifyError:(NSError *_Nonnull)error { - (void)notifyError:(NSError *)error block:(BugsnagOnErrorBlock)block { + bsg_log_debug(@"Notify called with %@", error); BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledError severity:BSGSeverityWarning attrValue:error.domain]; @@ -824,6 +829,7 @@ - (BOOL)appendNSErrorInfo:(NSError *)error } - (void)notify:(NSException *_Nonnull)exception { + bsg_log_debug(@"Notify called with %@", exception); BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledException]; [self notify:exception handledState:state block:nil]; @@ -832,6 +838,7 @@ - (void)notify:(NSException *_Nonnull)exception { - (void)notify:(NSException *)exception block:(BugsnagOnErrorBlock)block { + bsg_log_debug(@"Notify called with %@", exception); BugsnagHandledState *state = [BugsnagHandledState handledStateWithSeverityReason:HandledException]; [self notify:exception handledState:state block:block]; From f9b40810aae046ca7a0a7868e854ed458b98d9ef Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 22 Mar 2021 10:33:29 +0000 Subject: [PATCH 09/20] Fix context and groupingHash when loading persisted --- Bugsnag/Payload/BugsnagEvent.m | 2 ++ Tests/Data/BugsnagEvents/BugsnagEvent1.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Bugsnag/Payload/BugsnagEvent.m b/Bugsnag/Payload/BugsnagEvent.m index 3335d4dc8..51af6c3bb 100644 --- a/Bugsnag/Payload/BugsnagEvent.m +++ b/Bugsnag/Payload/BugsnagEvent.m @@ -186,9 +186,11 @@ - (instancetype)initWithJson:(NSDictionary *)json { if (self = [super init]) { _app = [BugsnagAppWithState appFromJson:json[BSGKeyApp]]; _breadcrumbs = BSGArrayMap(json[BSGKeyBreadcrumbs], ^id (NSDictionary *json) { return [BugsnagBreadcrumb breadcrumbFromDict:json]; }); + _context = json[BSGKeyContext]; _device = [BugsnagDeviceWithState deviceFromJson:json[BSGKeyDevice]]; _error = json[BSGKeyMetadata][BSGKeyError]; _errors = BSGArrayMap(json[BSGKeyExceptions], ^id (NSDictionary *json) { return [BugsnagError errorFromJson:json]; }); + _groupingHash = json[BSGKeyGroupingHash]; _handledState = [BugsnagHandledState handledStateFromJson:json]; _metadata = [[BugsnagMetadata alloc] initWithDictionary:json[BSGKeyMetadata]]; _session = [BugsnagSession fromJson:json[BSGKeySession]]; diff --git a/Tests/Data/BugsnagEvents/BugsnagEvent1.json b/Tests/Data/BugsnagEvents/BugsnagEvent1.json index 97b4b5289..5071604eb 100644 --- a/Tests/Data/BugsnagEvents/BugsnagEvent1.json +++ b/Tests/Data/BugsnagEvents/BugsnagEvent1.json @@ -1 +1 @@ -{"device":{"id":"5ed88ab6980274562bcd9106bd03e17810da3e79","orientation":"portrait","osName":"iOS","jailbroken":false,"osVersion":"14.3","time":"2021-01-19T11:16:25.000Z","locale":"en_US","runtimeVersions":{"osBuild":"19H114","clangVersion":"12.0.0 (clang-1200.0.32.28)"},"freeMemory":27904143360,"manufacturer":"Apple","freeDisk":551348178944,"modelNumber":"simulator","model":"iPod9,1","totalMemory":68715134976},"exceptions":[{"message":"-[ViewController someRandomMethod]: unrecognized selector sent to instance 0x7fbd4e51cc60","errorClass":"NSInvalidArgumentException","stacktrace":[{"method":"__exceptionPreprocess","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","isPC":true,"symbolAddress":"0x7fff20420a04","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20420ae6"},{"method":"objc_exception_throw","machoVMAddress":"0x7fff20172000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/libobjc.A.dylib","symbolAddress":"0x7fff20177e48","machoUUID":"0ED2E6A3-D7FC-3A31-A1CA-6BE106521240","machoLoadAddress":"0x7fff20172000","frameAddress":"0x7fff20177e78"},{"method":"-[NSObject(NSObject) doesNotRecognizeSelector:]","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2042f673","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2042f6f7"},{"method":"-[UIResponder doesNotRecognizeSelector:]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff246c5a33","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff246c5b57"},{"method":"___forwarding___","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20424a65","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20425036"},{"method":"_CF_forwarding_prep_0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20426ff0","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20427068"},{"method":"__NSThreadPerformPerform","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff208581ee","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff208582ba"},{"method":"__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f379","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f38a"},{"method":"__CFRunLoopDoSource0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f1ce","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f282"},{"method":"__CFRunLoopDoSources0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e66c","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e764"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20388f2f"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"GSEventRunModal","machoVMAddress":"0x7fff2bedb000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/GraphicsServices.framework\/GraphicsServices","symbolAddress":"0x7fff2beded28","machoUUID":"EFA60C9C-ACAF-3326-BDC5-4B361494A126","machoLoadAddress":"0x7fff2bedb000","frameAddress":"0x7fff2bededb3"},{"method":"-[UIApplication _run]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24690a7b","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24690e0b"},{"method":"UIApplicationMain","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24695c57","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24695cbc"},{"method":"_mh_execute_header","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2d0000","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2d1c70"},{"method":"start","machoVMAddress":"0x7fff20258000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libdyld.dylib","symbolAddress":"0x7fff202593e8","machoUUID":"78F65EE7-1659-3B52-9FE5-FDD6C61BDCAA","machoLoadAddress":"0x7fff20258000","frameAddress":"0x7fff202593e9"}],"type":"cocoa"}],"breadcrumbs":[{"timestamp":"2021-01-19T11:16:01.262Z","name":"Bugsnag loaded","type":"state","metaData":{}},{"timestamp":"2021-01-19T11:16:01.276Z","name":"Window Became Visible","type":"state","metaData":{}},{"timestamp":"2021-01-19T11:16:10.779Z","name":"Window Became Visible","type":"state","metaData":{}}],"app":{"bundleVersion":"4","durationInForeground":24000,"dsymUUIDs":["F18A2C56-008C-3CC1-8BFF-4E79683FB1AB"],"id":"bugsnag.Bugsnag-Test-App","inForeground":true,"isLaunching":false,"duration":24000,"version":"1.0","type":"iOS","releaseStage":"development"},"threads":[{"errorReportingThread":true,"id":"0","stacktrace":[{"method":"__exceptionPreprocess","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","isPC":true,"symbolAddress":"0x7fff20420a04","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20420ae6"},{"method":"objc_exception_throw","machoVMAddress":"0x7fff20172000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/libobjc.A.dylib","symbolAddress":"0x7fff20177e48","machoUUID":"0ED2E6A3-D7FC-3A31-A1CA-6BE106521240","machoLoadAddress":"0x7fff20172000","frameAddress":"0x7fff20177e78"},{"method":"-[NSObject(NSObject) doesNotRecognizeSelector:]","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2042f673","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2042f6f7"},{"method":"-[UIResponder doesNotRecognizeSelector:]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff246c5a33","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff246c5b57"},{"method":"___forwarding___","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20424a65","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20425036"},{"method":"_CF_forwarding_prep_0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20426ff0","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20427068"},{"method":"__NSThreadPerformPerform","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff208581ee","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff208582ba"},{"method":"__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f379","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f38a"},{"method":"__CFRunLoopDoSource0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f1ce","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f282"},{"method":"__CFRunLoopDoSources0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e66c","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e764"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20388f2f"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"GSEventRunModal","machoVMAddress":"0x7fff2bedb000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/GraphicsServices.framework\/GraphicsServices","symbolAddress":"0x7fff2beded28","machoUUID":"EFA60C9C-ACAF-3326-BDC5-4B361494A126","machoLoadAddress":"0x7fff2bedb000","frameAddress":"0x7fff2bededb3"},{"method":"-[UIApplication _run]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24690a7b","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24690e0b"},{"method":"UIApplicationMain","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24695c57","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24695cbc"},{"method":"_mh_execute_header","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2d0000","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2d1c70"},{"method":"start","machoVMAddress":"0x7fff20258000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libdyld.dylib","symbolAddress":"0x7fff202593e8","machoUUID":"78F65EE7-1659-3B52-9FE5-FDD6C61BDCAA","machoLoadAddress":"0x7fff20258000","frameAddress":"0x7fff202593e9"}],"type":"cocoa"},{"errorReportingThread":false,"id":"1","stacktrace":[{"method":"__workq_kernreturn","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c534c4","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c534ce"},{"method":"start_wqthread","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b68","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b77"}],"type":"cocoa"},{"errorReportingThread":false,"id":"2","stacktrace":[{"method":"__workq_kernreturn","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c534c4","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c534ce"},{"method":"start_wqthread","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b68","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b77"}],"type":"cocoa"},{"errorReportingThread":false,"id":"3","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"__CFRunLoopServiceMachPort","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e880","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e9bc"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203890c5"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"-[NSRunLoop(NSRunLoop) runMode:beforeDate:]","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff2082f6e8","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff2082f7b9"},{"method":"-[NSRunLoop(NSRunLoop) runUntilDate:]","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff2082f9e0","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff2082fa28"},{"method":"-[UIEventFetcher threadMain]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24747fa1","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24748171"},{"method":"__NSThread__start__","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff20857a56","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff20857e68"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"},{"errorReportingThread":false,"id":"4","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"thread_suspend","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c6f7dd","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c6f82d"},{"method":"__cxa_throw","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2de0b0","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2dee10"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"},{"errorReportingThread":false,"id":"5","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"__cxa_throw","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2de0b0","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2dee40"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"},{"errorReportingThread":false,"id":"6","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"__CFRunLoopServiceMachPort","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e880","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e9bc"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203890c5"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"_CFURLStorageSessionCopyCache","machoVMAddress":"0x7fff2350f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CFNetwork.framework\/CFNetwork","symbolAddress":"0x7fff2372af3f","machoUUID":"D9DAA7CF-DDC1-361B-A7AD-0D4783893E72","machoLoadAddress":"0x7fff2350f000","frameAddress":"0x7fff23739706"},{"method":"__NSThread__start__","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff20857a56","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff20857e68"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"}],"metaData":{"app":{"name":"Bugsnag Test App"},"device":{"orientation":"portrait","timezone":"GMT","wordSize":64,"simulator":true,"batteryLevel":-1,"charging":false},"error":{"nsexception":{"name":"NSInvalidArgumentException"},"reason":"-[ViewController someRandomMethod]: unrecognized selector sent to instance 0x7fbd4e51cc60","type":"nsexception","address":0},"user":{"id":"5ed88ab6980274562bcd9106bd03e17810da3e79"}},"unhandled":true,"session":{"id":"5C5C6908-726F-4CCE-A081-23BDA1157911","startedAt":"2021-01-19T11:16:01.259Z","events":{"handled":0,"unhandled":1}},"severity":"error","severityReason":{"type":"unhandledException"},"user":{"id":"5ed88ab6980274562bcd9106bd03e17810da3e79"}} +{"context": "customContext","groupingHash":"customGroupingHash","device":{"id":"5ed88ab6980274562bcd9106bd03e17810da3e79","orientation":"portrait","osName":"iOS","jailbroken":false,"osVersion":"14.3","time":"2021-01-19T11:16:25.000Z","locale":"en_US","runtimeVersions":{"osBuild":"19H114","clangVersion":"12.0.0 (clang-1200.0.32.28)"},"freeMemory":27904143360,"manufacturer":"Apple","freeDisk":551348178944,"modelNumber":"simulator","model":"iPod9,1","totalMemory":68715134976},"exceptions":[{"message":"-[ViewController someRandomMethod]: unrecognized selector sent to instance 0x7fbd4e51cc60","errorClass":"NSInvalidArgumentException","stacktrace":[{"method":"__exceptionPreprocess","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","isPC":true,"symbolAddress":"0x7fff20420a04","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20420ae6"},{"method":"objc_exception_throw","machoVMAddress":"0x7fff20172000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/libobjc.A.dylib","symbolAddress":"0x7fff20177e48","machoUUID":"0ED2E6A3-D7FC-3A31-A1CA-6BE106521240","machoLoadAddress":"0x7fff20172000","frameAddress":"0x7fff20177e78"},{"method":"-[NSObject(NSObject) doesNotRecognizeSelector:]","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2042f673","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2042f6f7"},{"method":"-[UIResponder doesNotRecognizeSelector:]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff246c5a33","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff246c5b57"},{"method":"___forwarding___","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20424a65","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20425036"},{"method":"_CF_forwarding_prep_0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20426ff0","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20427068"},{"method":"__NSThreadPerformPerform","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff208581ee","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff208582ba"},{"method":"__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f379","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f38a"},{"method":"__CFRunLoopDoSource0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f1ce","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f282"},{"method":"__CFRunLoopDoSources0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e66c","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e764"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20388f2f"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"GSEventRunModal","machoVMAddress":"0x7fff2bedb000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/GraphicsServices.framework\/GraphicsServices","symbolAddress":"0x7fff2beded28","machoUUID":"EFA60C9C-ACAF-3326-BDC5-4B361494A126","machoLoadAddress":"0x7fff2bedb000","frameAddress":"0x7fff2bededb3"},{"method":"-[UIApplication _run]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24690a7b","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24690e0b"},{"method":"UIApplicationMain","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24695c57","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24695cbc"},{"method":"_mh_execute_header","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2d0000","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2d1c70"},{"method":"start","machoVMAddress":"0x7fff20258000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libdyld.dylib","symbolAddress":"0x7fff202593e8","machoUUID":"78F65EE7-1659-3B52-9FE5-FDD6C61BDCAA","machoLoadAddress":"0x7fff20258000","frameAddress":"0x7fff202593e9"}],"type":"cocoa"}],"breadcrumbs":[{"timestamp":"2021-01-19T11:16:01.262Z","name":"Bugsnag loaded","type":"state","metaData":{}},{"timestamp":"2021-01-19T11:16:01.276Z","name":"Window Became Visible","type":"state","metaData":{}},{"timestamp":"2021-01-19T11:16:10.779Z","name":"Window Became Visible","type":"state","metaData":{}}],"app":{"bundleVersion":"4","durationInForeground":24000,"dsymUUIDs":["F18A2C56-008C-3CC1-8BFF-4E79683FB1AB"],"id":"bugsnag.Bugsnag-Test-App","inForeground":true,"isLaunching":false,"duration":24000,"version":"1.0","type":"iOS","releaseStage":"development"},"threads":[{"errorReportingThread":true,"id":"0","stacktrace":[{"method":"__exceptionPreprocess","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","isPC":true,"symbolAddress":"0x7fff20420a04","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20420ae6"},{"method":"objc_exception_throw","machoVMAddress":"0x7fff20172000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/libobjc.A.dylib","symbolAddress":"0x7fff20177e48","machoUUID":"0ED2E6A3-D7FC-3A31-A1CA-6BE106521240","machoLoadAddress":"0x7fff20172000","frameAddress":"0x7fff20177e78"},{"method":"-[NSObject(NSObject) doesNotRecognizeSelector:]","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2042f673","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2042f6f7"},{"method":"-[UIResponder doesNotRecognizeSelector:]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff246c5a33","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff246c5b57"},{"method":"___forwarding___","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20424a65","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20425036"},{"method":"_CF_forwarding_prep_0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20426ff0","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20427068"},{"method":"__NSThreadPerformPerform","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff208581ee","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff208582ba"},{"method":"__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f379","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f38a"},{"method":"__CFRunLoopDoSource0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038f1ce","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038f282"},{"method":"__CFRunLoopDoSources0","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e66c","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e764"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff20388f2f"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"GSEventRunModal","machoVMAddress":"0x7fff2bedb000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/GraphicsServices.framework\/GraphicsServices","symbolAddress":"0x7fff2beded28","machoUUID":"EFA60C9C-ACAF-3326-BDC5-4B361494A126","machoLoadAddress":"0x7fff2bedb000","frameAddress":"0x7fff2bededb3"},{"method":"-[UIApplication _run]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24690a7b","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24690e0b"},{"method":"UIApplicationMain","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24695c57","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24695cbc"},{"method":"_mh_execute_header","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2d0000","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2d1c70"},{"method":"start","machoVMAddress":"0x7fff20258000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libdyld.dylib","symbolAddress":"0x7fff202593e8","machoUUID":"78F65EE7-1659-3B52-9FE5-FDD6C61BDCAA","machoLoadAddress":"0x7fff20258000","frameAddress":"0x7fff202593e9"}],"type":"cocoa"},{"errorReportingThread":false,"id":"1","stacktrace":[{"method":"__workq_kernreturn","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c534c4","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c534ce"},{"method":"start_wqthread","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b68","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b77"}],"type":"cocoa"},{"errorReportingThread":false,"id":"2","stacktrace":[{"method":"__workq_kernreturn","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c534c4","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c534ce"},{"method":"start_wqthread","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b68","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b77"}],"type":"cocoa"},{"errorReportingThread":false,"id":"3","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"__CFRunLoopServiceMachPort","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e880","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e9bc"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203890c5"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"-[NSRunLoop(NSRunLoop) runMode:beforeDate:]","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff2082f6e8","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff2082f7b9"},{"method":"-[NSRunLoop(NSRunLoop) runUntilDate:]","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff2082f9e0","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff2082fa28"},{"method":"-[UIEventFetcher threadMain]","machoVMAddress":"0x7fff23a99000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/PrivateFrameworks\/UIKitCore.framework\/UIKitCore","symbolAddress":"0x7fff24747fa1","machoUUID":"984E55B9-03C9-3D2A-95DC-3A5F434A4A71","machoLoadAddress":"0x7fff23a99000","frameAddress":"0x7fff24748171"},{"method":"__NSThread__start__","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff20857a56","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff20857e68"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"},{"errorReportingThread":false,"id":"4","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"thread_suspend","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c6f7dd","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c6f82d"},{"method":"__cxa_throw","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2de0b0","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2dee10"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"},{"errorReportingThread":false,"id":"5","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"__cxa_throw","machoVMAddress":"0x100000000","machoFile":"\/Users\/nick\/Library\/Developer\/CoreSimulator\/Devices\/5AFE2FCA-EB57-45D2-A705-42F81D4031F3\/data\/Containers\/Bundle\/Application\/B7477EE0-B11B-41B3-9A7A-FFEE9E28AA47\/Bugsnag Test App.app\/Bugsnag Test App","symbolAddress":"0x10d2de0b0","machoUUID":"F18A2C56-008C-3CC1-8BFF-4E79683FB1AB","machoLoadAddress":"0x10d2d0000","frameAddress":"0x10d2dee40"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"},{"errorReportingThread":false,"id":"6","stacktrace":[{"method":"mach_msg_trap","machoVMAddress":"0x7fff60c51000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_kernel.dylib","symbolAddress":"0x7fff60c51df0","machoUUID":"FF092EE8-5BEE-3B9A-8749-F0A067115C7E","machoLoadAddress":"0x7fff60c51000","frameAddress":"0x7fff60c51dfa"},{"method":"__CFRunLoopServiceMachPort","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038e880","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff2038e9bc"},{"method":"__CFRunLoopRun","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff20388bc1","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203890c5"},{"method":"CFRunLoopRunSpecific","machoVMAddress":"0x7fff2030f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CoreFoundation.framework\/CoreFoundation","symbolAddress":"0x7fff2038849f","machoUUID":"8FC68AD0-5128-3700-9E63-F6F358B6321B","machoLoadAddress":"0x7fff2030f000","frameAddress":"0x7fff203886d6"},{"method":"_CFURLStorageSessionCopyCache","machoVMAddress":"0x7fff2350f000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/CFNetwork.framework\/CFNetwork","symbolAddress":"0x7fff2372af3f","machoUUID":"D9DAA7CF-DDC1-361B-A7AD-0D4783893E72","machoLoadAddress":"0x7fff2350f000","frameAddress":"0x7fff23739706"},{"method":"__NSThread__start__","machoVMAddress":"0x7fff2071b000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/System\/Library\/Frameworks\/Foundation.framework\/Foundation","symbolAddress":"0x7fff20857a56","machoUUID":"5716A8B8-2769-3484-9FD8-196630050F5B","machoLoadAddress":"0x7fff2071b000","frameAddress":"0x7fff20857e68"},{"method":"_pthread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c8e075","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c8e109"},{"method":"thread_start","machoVMAddress":"0x7fff60c88000","machoFile":"\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime\/Contents\/Resources\/RuntimeRoot\/usr\/lib\/system\/libsystem_pthread.dylib","symbolAddress":"0x7fff60c89b7c","machoUUID":"62CB1A98-0B8F-31E7-A02B-A1139927F61D","machoLoadAddress":"0x7fff60c88000","frameAddress":"0x7fff60c89b8b"}],"type":"cocoa"}],"metaData":{"app":{"name":"Bugsnag Test App"},"device":{"orientation":"portrait","timezone":"GMT","wordSize":64,"simulator":true,"batteryLevel":-1,"charging":false},"error":{"nsexception":{"name":"NSInvalidArgumentException"},"reason":"-[ViewController someRandomMethod]: unrecognized selector sent to instance 0x7fbd4e51cc60","type":"nsexception","address":0},"user":{"id":"5ed88ab6980274562bcd9106bd03e17810da3e79"}},"unhandled":true,"session":{"id":"5C5C6908-726F-4CCE-A081-23BDA1157911","startedAt":"2021-01-19T11:16:01.259Z","events":{"handled":0,"unhandled":1}},"severity":"error","severityReason":{"type":"unhandledException"},"user":{"id":"5ed88ab6980274562bcd9106bd03e17810da3e79"}} From d1c7b92d91a388730f746157cebd8451d06b7ec9 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 22 Mar 2021 11:32:51 +0000 Subject: [PATCH 10/20] Fix build warning --- Bugsnag/Client/BugsnagClient.m | 14 +++++++++----- features/fixtures/ios-swift-cocoapods/Podfile | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index 5dbcfba43..a3b7963fb 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -560,26 +560,30 @@ - (void)addTerminationObserver:(NSString *)name { } - (void)computeDidCrashLastLaunch { + BOOL didCrash = NO; + // Did the app crash in a way that was detected by KSCrash? if (bsg_kscrashstate_currentState()->crashedLastLaunch || !access(crashSentinelPath, F_OK)) { bsg_log_info(@"Last run terminated due to a crash."); unlink(crashSentinelPath); - self.appDidCrashLastLaunch = YES; + didCrash = YES; } // Was the app terminated while the main thread was hung? else if ((self.eventFromLastLaunch = [self loadFatalAppHangEvent])) { bsg_log_info(@"Last run terminated during an app hang."); - self.appDidCrashLastLaunch = YES; + didCrash = YES; } // Was the app terminated while in the foreground? (probably an OOM) else if ([self shouldReportOOM]) { bsg_log_info(@"Last run terminated abnormally; likely Out Of Memory."); self.eventFromLastLaunch = [self generateOutOfMemoryEvent]; - self.appDidCrashLastLaunch = YES; + didCrash = YES; } + self.appDidCrashLastLaunch = didCrash; + BOOL wasLaunching = [self.stateMetadataFromLastLaunch[BSGKeyApp][BSGKeyIsLaunching] boolValue]; - BOOL didCrashDuringLaunch = self.appDidCrashLastLaunch && wasLaunching; + BOOL didCrashDuringLaunch = didCrash && wasLaunching; if (didCrashDuringLaunch) { self.systemState.consecutiveLaunchCrashes++; } else { @@ -587,7 +591,7 @@ - (void)computeDidCrashLastLaunch { } self.lastRunInfo = [[BugsnagLastRunInfo alloc] initWithConsecutiveLaunchCrashes:self.systemState.consecutiveLaunchCrashes - crashed:self.appDidCrashLastLaunch + crashed:didCrash crashedDuringLaunch:didCrashDuringLaunch]; } diff --git a/features/fixtures/ios-swift-cocoapods/Podfile b/features/fixtures/ios-swift-cocoapods/Podfile index 0dbe376ed..df3263070 100644 --- a/features/fixtures/ios-swift-cocoapods/Podfile +++ b/features/fixtures/ios-swift-cocoapods/Podfile @@ -17,6 +17,7 @@ post_install do |installer| if target.name == "Bugsnag" target.build_configurations.each do |config| config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BSG_LOG_LEVEL=BSG_LOGLEVEL_DEBUG'] + config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES' end end end From d2be7b7510d6f9680a7758dc92ab0f218a685734 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 22 Mar 2021 16:06:07 +0000 Subject: [PATCH 11/20] Remove redundant conditional --- .../KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c index bf81673ea..daaba03f7 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c @@ -1245,11 +1245,8 @@ void bsg_kscrw_i_writeError(const BSG_KSCrashReportWriter *const writer, writer->beginObject(writer, key); { - - if (crash->crashType) { - writer->addUIntegerElement(writer, BSG_KSCrashField_Address, - crash->faultAddress); - } + writer->addUIntegerElement(writer, BSG_KSCrashField_Address, + crash->faultAddress); if (crashReason != NULL) { writer->addStringElement(writer, BSG_KSCrashField_Reason, From 8ee1ba0a5aadefb0e3f7b4238471d9452c0538c1 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Thu, 25 Mar 2021 15:23:39 +0000 Subject: [PATCH 12/20] Improve performance of deserializing breadcrumbs --- Bugsnag/Helpers/BSG_RFC3339DateTool.h | 7 ++++++ Bugsnag/Helpers/BSG_RFC3339DateTool.m | 24 +++++++++++++++++++++ Bugsnag/Payload/BugsnagBreadcrumb.m | 31 +++++++++++++++++++++------ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Bugsnag/Helpers/BSG_RFC3339DateTool.h b/Bugsnag/Helpers/BSG_RFC3339DateTool.h index 6adf35271..046a1c0ed 100644 --- a/Bugsnag/Helpers/BSG_RFC3339DateTool.h +++ b/Bugsnag/Helpers/BSG_RFC3339DateTool.h @@ -53,4 +53,11 @@ */ + (NSString *)stringFromUNIXTimestamp:(unsigned long long)timestamp; +/** + * Determines whether a string might contain an RFC3339 formatted date. + * + * Useful if the overhead of -dateFromString: needs to be avoided. + */ ++ (BOOL)isLikelyDateString:(NSString *)string; + @end diff --git a/Bugsnag/Helpers/BSG_RFC3339DateTool.m b/Bugsnag/Helpers/BSG_RFC3339DateTool.m index 49558d088..eeb8db326 100644 --- a/Bugsnag/Helpers/BSG_RFC3339DateTool.m +++ b/Bugsnag/Helpers/BSG_RFC3339DateTool.m @@ -86,4 +86,28 @@ + (NSString *)stringFromUNIXTimestamp:(unsigned long long)timestamp { [self stringFromDate:[NSDate dateWithTimeIntervalSince1970:timestamp]]; } ++ (BOOL)isLikelyDateString:(NSString *)string { + const char *ptr = string.UTF8String; + return (string.length >= 19 && + isdigit(ptr[0]) && + isdigit(ptr[1]) && + isdigit(ptr[2]) && + isdigit(ptr[3]) && + '-' == (ptr[4]) && + isdigit(ptr[5]) && + isdigit(ptr[6]) && + '-' == (ptr[7]) && + isdigit(ptr[8]) && + isdigit(ptr[9]) && + 'T' == ptr[10] && + isdigit(ptr[11]) && + isdigit(ptr[12]) && + ':' == (ptr[13]) && + isdigit(ptr[14]) && + isdigit(ptr[15]) && + ':' == (ptr[16]) && + isdigit(ptr[17]) && + isdigit(ptr[18])); +} + @end diff --git a/Bugsnag/Payload/BugsnagBreadcrumb.m b/Bugsnag/Payload/BugsnagBreadcrumb.m index 56ecac5d2..ff7a042b2 100644 --- a/Bugsnag/Payload/BugsnagBreadcrumb.m +++ b/Bugsnag/Payload/BugsnagBreadcrumb.m @@ -74,6 +74,15 @@ BSGBreadcrumbType BSGBreadcrumbTypeFromString(NSString *value) { } } + +@interface BugsnagBreadcrumb () + +/// String representation of `timestamp` used to avoid unnecessary date <--> string conversions +@property (copy, nonatomic) NSString *timestampString; + +@end + + @implementation BugsnagBreadcrumb - (instancetype)init { @@ -86,12 +95,12 @@ - (instancetype)init { } - (BOOL)isValid { - return self.message.length > 0 && self.timestamp != nil; + return self.message.length > 0 && (self.timestampString || self.timestamp); } - (NSDictionary *)objectValue { @synchronized (self) { - NSString *timestamp = [BSG_RFC3339DateTool stringFromDate:_timestamp]; + NSString *timestamp = self.timestampString ?: [BSG_RFC3339DateTool stringFromDate:self.timestamp]; if (timestamp && _message.length > 0) { NSMutableDictionary *metadata = [NSMutableDictionary new]; for (NSString *key in _metadata) { @@ -112,17 +121,24 @@ - (NSDictionary *)objectValue { @synthesize timestamp = _timestamp; +// The timestamp is lazily computed from the timestampString to avoid unnecessary +// calls to -dateFromString: (which is expensive) when loading breadcrumbs from disk. + - (NSDate *)timestamp { @synchronized (self) { + if (!_timestamp) { + _timestamp = [BSG_RFC3339DateTool dateFromString:self.timestampString]; + } return _timestamp; } } -- (void)setTimestamp:(NSDate * _Nullable)timestamp { +@synthesize timestampString = _timestampString; + +- (void)setTimestampString:(NSString *)timestampString { @synchronized (self) { - [self willChangeValueForKey:NSStringFromSelector(@selector(timestamp))]; - _timestamp = timestamp; - [self didChangeValueForKey:NSStringFromSelector(@selector(timestamp))]; + _timestampString = [timestampString copy]; + _timestamp = nil; } } @@ -200,6 +216,7 @@ + (instancetype)breadcrumbWithBlock:(BSGBreadcrumbConfiguration)block { + (instancetype)breadcrumbFromDict:(NSDictionary *)dict { BOOL isValidCrumb = [dict[BSGKeyType] isKindOfClass:[NSString class]] && [dict[BSGKeyTimestamp] isKindOfClass:[NSString class]] + && [BSG_RFC3339DateTool isLikelyDateString:dict[BSGKeyTimestamp]] && ( [dict[BSGKeyMetadata] isKindOfClass:[NSDictionary class]] || [dict[@"metadata"] isKindOfClass:[NSDictionary class]] // react-native uses lowercase key @@ -211,7 +228,7 @@ + (instancetype)breadcrumbFromDict:(NSDictionary *)dict { return [self breadcrumbWithBlock:^(BugsnagBreadcrumb *crumb) { crumb.message = dict[BSGKeyMessage] ?: dict[BSGKeyName]; crumb.metadata = dict[BSGKeyMetadata] ?: dict[@"metadata"]; - crumb.timestamp = [BSG_RFC3339DateTool dateFromString:dict[BSGKeyTimestamp]]; + crumb.timestampString = dict[BSGKeyTimestamp]; crumb.type = BSGBreadcrumbTypeFromString(dict[BSGKeyType]); }]; } From bb296b99f6355b7b40a5c6f6e7052b5a943f3448 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 26 Mar 2021 08:20:12 +0000 Subject: [PATCH 13/20] Fix OCLint warning --- Bugsnag/Payload/BugsnagBreadcrumb.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bugsnag/Payload/BugsnagBreadcrumb.m b/Bugsnag/Payload/BugsnagBreadcrumb.m index ff7a042b2..5027d1153 100644 --- a/Bugsnag/Payload/BugsnagBreadcrumb.m +++ b/Bugsnag/Payload/BugsnagBreadcrumb.m @@ -138,7 +138,7 @@ - (NSDate *)timestamp { - (void)setTimestampString:(NSString *)timestampString { @synchronized (self) { _timestampString = [timestampString copy]; - _timestamp = nil; + _timestamp = nil; //!OCLint } } From 0d5b84c412b4ae808f5e7e69d0917b40139579b1 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 26 Mar 2021 10:18:56 +0000 Subject: [PATCH 14/20] Fix flake in AutoSessionMixedEventsScenario due to race condition --- features/fixtures/shared/scenarios/Scenario.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/features/fixtures/shared/scenarios/Scenario.m b/features/fixtures/shared/scenarios/Scenario.m index 8680e0963..44a2666a2 100644 --- a/features/fixtures/shared/scenarios/Scenario.m +++ b/features/fixtures/shared/scenarios/Scenario.m @@ -113,9 +113,10 @@ - (void)performBlockAndWaitForEventDelivery:(dispatch_block_t)block { } - (void)requestDidComplete:(NSURLRequest *)request { - if (_onEventDelivery && [request.URL.absoluteString isEqual:self.config.endpoints.notify]) { - _onEventDelivery(); + dispatch_block_t block = _onEventDelivery; + if (block && [request.URL.absoluteString isEqual:self.config.endpoints.notify]) { _onEventDelivery = nil; + block(); } } From 2613411b769a163398a5d4fe294a6bc3dc730bb6 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Fri, 26 Mar 2021 15:20:31 +0000 Subject: [PATCH 15/20] Detect uncaught objc exceptions on Mac Catalyst and iOSAppOnMac --- .../Sentry/BSG_KSCrashSentry_NSException.m | 67 +++++++++++++++++++ CHANGELOG.md | 7 ++ 2 files changed, 74 insertions(+) diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m index cf181a03e..3389c7629 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m @@ -32,6 +32,8 @@ //#define BSG_KSLogger_LocalLevel TRACE #import "BSG_KSLogger.h" +#import + // ============================================================================ #pragma mark - Globals - // ============================================================================ @@ -130,9 +132,53 @@ void bsg_recordException(NSException *exception) { BSG_KSLOG_DEBUG(@"Calling main crash handler."); bsg_g_context->onCrash(crashContext()); + + bsg_kscrashsentry_resumeThreads(); } } +// ============================================================================ +#pragma mark - iOS apps on macOS - +// ============================================================================ + +// iOS apps behave a little differently when running on macOS via Catalyst or +// on Apple Silicon. Uncaught NSExceptions raised while handling UI events get +// caught by AppKit and are not propagated to NSUncaughtExceptionHandler or +// std::terminate_handler, therefore we need another way to detect them... + +#if TARGET_OS_IOS + +static Method NSApplication_reportException; + +/// Pointer to the real implementation of -[NSApplication reportException:] +static void (* NSApplication_reportException_imp)(id, SEL, NSException *); + +/// Overrides -[NSApplication reportException:] +static void bsg_reportException(id self, SEL _cmd, NSException *exception) { + BSG_KSLOG_DEBUG(@"reportException: %@", exception); + + bsg_kscrashsentry_beginHandlingCrash(bsg_g_context); + + bsg_recordException(exception); + +#if TARGET_OS_MACCATALYST + // Mac Catalyst apps continue to run after an uncaught exception is thrown + // while handling a UI event. Our crash sentries should remain installed to + // catch any subsequent unhandled exceptions or crashes. +#else + // iOS apps running on Apple Silicon Macs terminate with an EXC_BREAKPOINT + // mach exception. We don't want to catch that because its stack trace will + // not point to where the exception was raised (its top frame will be + // -[NSApplication _crashOnException:]) so we should uninstall our crash + // sentries. + bsg_kscrashsentry_uninstall(BSG_KSCrashTypeAll); +#endif + + NSApplication_reportException_imp(self, _cmd, exception); +} + +#endif + // ============================================================================ #pragma mark - API - // ============================================================================ @@ -153,6 +199,18 @@ bool bsg_kscrashsentry_installNSExceptionHandler( BSG_KSLOG_DEBUG(@"Setting new handler."); NSSetUncaughtExceptionHandler(&bsg_ksnsexc_i_handleException); +#if TARGET_OS_IOS + NSApplication_reportException = + class_getInstanceMethod(NSClassFromString(@"NSApplication"), + NSSelectorFromString(@"reportException:")); + if (NSApplication_reportException) { + BSG_KSLOG_DEBUG(@"Overriding -[NSApplication reportException:]"); + NSApplication_reportException_imp = (void *) + method_setImplementation(NSApplication_reportException, + (IMP)bsg_reportException); + } +#endif + return true; } @@ -164,5 +222,14 @@ void bsg_kscrashsentry_uninstallNSExceptionHandler(void) { BSG_KSLOG_DEBUG(@"Restoring original handler."); NSSetUncaughtExceptionHandler(bsg_g_previousUncaughtExceptionHandler); + +#if TARGET_OS_IOS + if (NSApplication_reportException && NSApplication_reportException_imp) { + BSG_KSLOG_DEBUG(@"Restoring original -[NSApplication reportException:]"); + method_setImplementation(NSApplication_reportException, + (IMP)NSApplication_reportException_imp); + } +#endif + bsg_g_installed = 0; } diff --git a/CHANGELOG.md b/CHANGELOG.md index 827c91b03..cf84ccae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Changelog ========= +## TBD + +### Bug fixes + +* Uncaught exceptions thrown while handing UI events in iOS apps running on macOS are now detected. + [#1053](https://github.com/bugsnag/bugsnag-cocoa/pull/1053) + ## 6.8.1 (2021-03-24) ### Bug fixes From bc0a3eb103fbade0f550eb6c32d719e870cdb043 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Mon, 29 Mar 2021 11:34:55 +0100 Subject: [PATCH 16/20] Mention FB8901200 in comment --- .../KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m index 3389c7629..d883a343f 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m @@ -144,7 +144,8 @@ void bsg_recordException(NSException *exception) { // iOS apps behave a little differently when running on macOS via Catalyst or // on Apple Silicon. Uncaught NSExceptions raised while handling UI events get // caught by AppKit and are not propagated to NSUncaughtExceptionHandler or -// std::terminate_handler, therefore we need another way to detect them... +// std::terminate_handler (reported to Apple: FB8901200) therefore we need +// another way to detect them... #if TARGET_OS_IOS From b7dbe7033b4868488f45698d811bf7a82014b353 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Tue, 30 Mar 2021 13:46:15 +0100 Subject: [PATCH 17/20] Report macOS version and device model for iOS / Catalyst apps --- Bugsnag/Helpers/BugsnagKeys.h | 3 - Bugsnag/Helpers/BugsnagKeys.m | 3 - .../Source/KSCrash/Recording/BSG_Jailbreak.h | 4 +- .../KSCrash/Recording/BSG_KSSystemInfo.m | 130 ++++++++++++++---- CHANGELOG.md | 4 + Tests/BugsnagClientPayloadInfoTest.m | 28 ++-- 6 files changed, 126 insertions(+), 46 deletions(-) diff --git a/Bugsnag/Helpers/BugsnagKeys.h b/Bugsnag/Helpers/BugsnagKeys.h index d74aaabf9..1b3ac99c6 100644 --- a/Bugsnag/Helpers/BugsnagKeys.h +++ b/Bugsnag/Helpers/BugsnagKeys.h @@ -45,8 +45,6 @@ extern NSString *const BSGKeyExtraRuntimeInfo; extern NSString *const BSGKeyFrameAddress; extern NSString *const BSGKeyFrameAddrFormat; extern NSString *const BSGKeyGroupingHash; -extern NSString *const BSGKeyHwMachine; -extern NSString *const BSGKeyHwModel; extern NSString *const BSGKeyId; extern NSString *const BSGKeyImageAddress; extern NSString *const BSGKeyImageVmAddress; @@ -89,7 +87,6 @@ extern NSString *const BSGKeySessionsEndpoint; extern NSString *const BSGKeySeverity; extern NSString *const BSGKeySeverityReason; extern NSString *const BSGKeySignal; -extern NSString *const BSGKeySimulatorModelId; extern NSString *const BSGKeyStacktrace; extern NSString *const BSGKeySymbolAddr; extern NSString *const BSGKeySymbolAddress; diff --git a/Bugsnag/Helpers/BugsnagKeys.m b/Bugsnag/Helpers/BugsnagKeys.m index 66168d0e1..2bbf2c6ac 100644 --- a/Bugsnag/Helpers/BugsnagKeys.m +++ b/Bugsnag/Helpers/BugsnagKeys.m @@ -41,8 +41,6 @@ NSString *const BSGKeyFrameAddress = @"frameAddress"; NSString *const BSGKeyFrameAddrFormat = @"0x%lx"; NSString *const BSGKeyGroupingHash = @"groupingHash"; -NSString *const BSGKeyHwMachine = @"hw.machine"; -NSString *const BSGKeyHwModel = @"hw.model"; NSString *const BSGKeyId = @"id"; NSString *const BSGKeyImageAddress = @"image_addr"; NSString *const BSGKeyImageVmAddress = @"image_vmaddr"; @@ -85,7 +83,6 @@ NSString *const BSGKeySeverity = @"severity"; NSString *const BSGKeySeverityReason = @"severityReason"; NSString *const BSGKeySignal = @"signal"; -NSString *const BSGKeySimulatorModelId = @"SIMULATOR_MODEL_IDENTIFIER"; NSString *const BSGKeyStacktrace = @"stacktrace"; NSString *const BSGKeySymbolAddr = @"symbolAddress"; NSString *const BSGKeySymbolAddress = @"symbol_addr"; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h index a837d9e2c..968950a06 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_Jailbreak.h @@ -104,7 +104,7 @@ static inline bool bsg_local_is_insert_libraries_env_var(const char* str) { } \ } while(0) -#elif TARGET_CPU_X86_64 +#elif TARGET_CPU_X86_64 && __GCC_ASM_FLAG_OUTPUTS__ #define BSG_HAS_CUSTOM_SYSCALL 1 // X86_64 3-parameter syscall @@ -114,6 +114,8 @@ static inline bool bsg_local_is_insert_libraries_env_var(const char* str) { // - Syscall# is in RAX, params in RDI, RSI, RDX, and return in RAX. // - Carry bit is cleared on success, set on failure. // - We must also inform the compiler that memory, rcx, r11 may get clobbered. +// The "=@ccc" constraint requires __GCC_ASM_FLAG_OUTPUTS__, not available in Xcode 10 +// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#index-asm-flag-output-operands #define bsg_syscall3(call_num, param0, param1, param2, pResult) do { \ register uintptr_t rax = (uintptr_t)(call_num) | (2<<24); \ register uintptr_t p0 = (uintptr_t)(param0); \ diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m index 35afa7b50..783abb4b4 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m @@ -63,6 +63,48 @@ static inline bool is_jailbroken() { return is_jb; } +/** + * Returns the content of /System/Library/CoreServices/SystemVersion.plist + * bypassing the open syscall shim that would normally redirect access to this + * file for iOS apps running on macOS. + * + * https://opensource.apple.com/source/xnu/xnu-7195.81.3/libsyscall/wrappers/system-version-compat.c.auto.html + */ +static NSDictionary * bsg_systemversion() { + static NSDictionary *systemVersion; + if (!systemVersion) { + int fd = -1; + char buffer[1024] = {0}; + const char *file = "/System/Library/CoreServices/SystemVersion.plist"; + bsg_syscall_open(file, O_RDONLY, 0, &fd); + if (fd < 0) { + BSG_KSLOG_ERROR("Could not open SystemVersion.plist"); + return nil; + } + ssize_t length = read(fd, buffer, sizeof(buffer)); + close(fd); + if (length < 0 || length == sizeof(buffer)) { + BSG_KSLOG_ERROR("Could not read SystemVersion.plist"); + return nil; + } + NSData *data = [NSData + dataWithBytesNoCopy:buffer + length:length freeWhenDone:NO]; + if (!data) { + BSG_KSLOG_ERROR("Could not read SystemVersion.plist"); + return nil; + } + NSError *error = nil; + systemVersion = [NSPropertyListSerialization + propertyListWithData:data + options:0 format:NULL error:&error]; + if (!systemVersion) { + BSG_KSLOG_ERROR("Could not read SystemVersion.plist: %@", error); + } + } + return systemVersion; +} + @implementation BSG_KSSystemInfo // ============================================================================ @@ -207,9 +249,9 @@ + (NSString *)deviceAndAppHash { } // Append some device-specific data. - [data appendData:(NSData * _Nonnull)[[self stringSysctl:BSGKeyHwMachine] + [data appendData:(NSData * _Nonnull)[[self stringSysctl:@"hw.machine"] dataUsingEncoding:NSUTF8StringEncoding]]; - [data appendData:(NSData * _Nonnull)[[self stringSysctl:BSGKeyHwModel] + [data appendData:(NSData * _Nonnull)[[self stringSysctl:@"hw.model"] dataUsingEncoding:NSUTF8StringEncoding]]; [data appendData:(NSData * _Nonnull)[[self currentCPUArch] dataUsingEncoding:NSUTF8StringEncoding]]; @@ -371,6 +413,13 @@ + (NSDictionary *)systemInfo { #ifdef __clang_version__ sysInfo[@BSG_KSSystemField_ClangVersion] = @__clang_version__; #endif + +#if TARGET_OS_SIMULATOR + // + // When running on the simulator, we want to report the name and version of + // the simlated OS. + // + #if TARGET_OS_IOS // Note: This does not match UIDevice.currentDevice.systemName for versions // prior to (and some versions of) iOS 9 where the systemName was reported @@ -379,40 +428,61 @@ + (NSDictionary *)systemInfo { // the information we need but will contain the macOS information when // running on the Simulator. sysInfo[@BSG_KSSystemField_SystemName] = @"iOS"; -#elif TARGET_OS_OSX - sysInfo[@BSG_KSSystemField_SystemName] = @"Mac OS"; #elif TARGET_OS_TV sysInfo[@BSG_KSSystemField_SystemName] = @"tvOS"; -#endif - NSOperatingSystemVersion version = - [NSProcessInfo processInfo].operatingSystemVersion; - NSString *systemVersion; - if (version.patchVersion == 0) { - systemVersion = - [NSString stringWithFormat:@"%ld.%ld", - (long)version.majorVersion, (long)version.minorVersion]; - } else { - systemVersion = - [NSString stringWithFormat:@"%ld.%ld.%ld", - (long)version.majorVersion, (long)version.minorVersion, - (long)version.patchVersion]; +#endif // TARGET_OS_IOS + + NSDictionary *env = NSProcessInfo.processInfo.environment; + sysInfo[@(BSG_KSSystemField_SystemVersion)] = env[@"SIMULATOR_RUNTIME_VERSION"]; + sysInfo[@(BSG_KSSystemField_Machine)] = env[@"SIMULATOR_MODEL_IDENTIFIER"]; + sysInfo[@(BSG_KSSystemField_Model)] = @"simulator"; + +#else // !TARGET_OS_SIMULATOR + + // + // Report the name and version of the underlying OS the app is running on. + // For Mac Catalyst and iOS apps running on macOS, this means macOS rather + // than the version of iOS it emulates ("iOSSupportVersion") + // + NSDictionary *sysVersion = bsg_systemversion(); + +#if TARGET_OS_IOS || TARGET_OS_OSX + NSString *systemName = sysVersion[@"ProductName"]; + if ([systemName isEqual:@"iPhone OS"]) { + systemName = @"iOS"; + } else if + // "ProductName" changed from "Mac OS X" to "macOS" in 11.0 + ([systemName isEqual:@"macOS"] || [systemName isEqual:@"Mac OS X"]) { + // KSCrash had the name hard-coded this way when we forked it. + systemName = @"Mac OS"; } - sysInfo[@BSG_KSSystemField_SystemVersion] = systemVersion; +#elif TARGET_OS_TV + NSString *systemName = @"tvOS"; +#endif + + sysInfo[@(BSG_KSSystemField_SystemName)] = systemName; + sysInfo[@(BSG_KSSystemField_SystemVersion)] = sysVersion[@"ProductVersion"]; - if ([self isSimulatorBuild]) { - NSString *model = [NSProcessInfo processInfo] - .environment[BSGKeySimulatorModelId]; - sysInfo[@BSG_KSSystemField_Machine] = model; - sysInfo[@BSG_KSSystemField_Model] = @"simulator"; + // Bugsnag payload mapping: + // + // BSG_KSSystemField_Machine => device.model + // BSG_KSSystemField_Model => device.modelNumber + + if ([systemName isEqual:@"Mac OS"]) { + // On macOS hw.model contains the "Model Identifier" e.g. MacBookPro16,1 + sysInfo[@(BSG_KSSystemField_Machine)] = [self stringSysctl:@"hw.model"]; + // and hw.machine contains the instruction set - e.g. "arm64" or "x86_64" + // we omit this since it doesn't match what we're expecting or want. } else { -#if BSG_PLATFORM_OSX - // MacOS has the machine in the model field, and no model - sysInfo[@BSG_KSSystemField_Machine] = [self stringSysctl:BSGKeyHwModel]; -#else - sysInfo[@BSG_KSSystemField_Machine] = [self stringSysctl:BSGKeyHwMachine]; - sysInfo[@BSG_KSSystemField_Model] = [self stringSysctl:BSGKeyHwModel]; -#endif + // On iOS & tvOS hw.machine contains the "Model Identifier" or + // "ProductType" - e.g. "iPhone6,1" + sysInfo[@(BSG_KSSystemField_Machine)] = [self stringSysctl:@"hw.machine"]; + // and hw.model contains the "Internal Name" or "Board ID" - e.g. "D79AP" + sysInfo[@(BSG_KSSystemField_Model)] = [self stringSysctl:@"hw.model"]; } + +#endif // TARGET_OS_SIMULATOR + sysInfo[@BSG_KSSystemField_KernelVersion] = [self stringSysctl:@"kern.version"]; sysInfo[@BSG_KSSystemField_OSVersion] = [self osBuildVersion]; sysInfo[@BSG_KSSystemField_Jailbroken] = @([self isJailbroken]); diff --git a/CHANGELOG.md b/CHANGELOG.md index cf84ccae0..bd033a780 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ Changelog ### Bug fixes +* `osName` and `osVersion` now reflect the Mac's OS when running Mac Catalyst apps or iOS apps running on macOS. + Fix reporting of `model` for Mac Catalyst apps or iOS apps running on macOS. + [#1054](https://github.com/bugsnag/bugsnag-cocoa/pull/1054) + * Uncaught exceptions thrown while handing UI events in iOS apps running on macOS are now detected. [#1053](https://github.com/bugsnag/bugsnag-cocoa/pull/1053) diff --git a/Tests/BugsnagClientPayloadInfoTest.m b/Tests/BugsnagClientPayloadInfoTest.m index 21341f71b..ba1dedca0 100755 --- a/Tests/BugsnagClientPayloadInfoTest.m +++ b/Tests/BugsnagClientPayloadInfoTest.m @@ -47,17 +47,27 @@ - (void)testAppInfo { - (void)testDeviceInfo { BugsnagClient *client = [Bugsnag client]; NSDictionary *device = [client collectDeviceWithState]; - XCTAssertNotNil(device); - - NSArray *observedKeys = [[device allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; - NSMutableArray *expectedKeys = [@[@"freeDisk", @"freeMemory", @"id", @"jailbroken", @"locale", @"manufacturer", - @"model", @"osName", @"osVersion", @"runtimeVersions", @"time", @"totalMemory"] mutableCopy]; - + XCTAssertNotNil(device[@"freeDisk"]); + XCTAssertNotNil(device[@"freeMemory"]); + XCTAssertNotNil(device[@"id"]); + XCTAssertNotNil(device[@"jailbroken"]); + XCTAssertNotNil(device[@"locale"]); + XCTAssertNotNil(device[@"manufacturer"]); + XCTAssertNotNil(device[@"model"]); + XCTAssertNotNil(device[@"osName"]); + XCTAssertNotNil(device[@"osVersion"]); + XCTAssertNotNil(device[@"runtimeVersions"]); + XCTAssertNotNil(device[@"time"]); + XCTAssertNotNil(device[@"totalMemory"]); + #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE - [expectedKeys addObject:@"modelNumber"]; + NSProcessInfo *processInfo = NSProcessInfo.processInfo; + BOOL isOnMac = [processInfo respondsToSelector:NSSelectorFromString(@"isMacCatalystApp")] && + [[processInfo valueForKey:@"isMacCatalystApp"] boolValue]; + if (!isOnMac) { + XCTAssertNotNil(device[@"modelNumber"]); + } #endif - - XCTAssertEqualObjects(observedKeys, [expectedKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]); } - (void)testBreadcrumbInfo { From 84dcbe2c0f22d6cd015f82acc79ebeff7c708fac Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Tue, 30 Mar 2021 15:19:29 +0100 Subject: [PATCH 18/20] Use dispatch_once --- .../Source/KSCrash/Recording/BSG_KSSystemInfo.m | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m index 783abb4b4..647ef4a4f 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m @@ -72,27 +72,28 @@ static inline bool is_jailbroken() { */ static NSDictionary * bsg_systemversion() { static NSDictionary *systemVersion; - if (!systemVersion) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ int fd = -1; char buffer[1024] = {0}; const char *file = "/System/Library/CoreServices/SystemVersion.plist"; bsg_syscall_open(file, O_RDONLY, 0, &fd); if (fd < 0) { BSG_KSLOG_ERROR("Could not open SystemVersion.plist"); - return nil; + return; } ssize_t length = read(fd, buffer, sizeof(buffer)); close(fd); if (length < 0 || length == sizeof(buffer)) { BSG_KSLOG_ERROR("Could not read SystemVersion.plist"); - return nil; + return; } NSData *data = [NSData dataWithBytesNoCopy:buffer length:length freeWhenDone:NO]; if (!data) { BSG_KSLOG_ERROR("Could not read SystemVersion.plist"); - return nil; + return; } NSError *error = nil; systemVersion = [NSPropertyListSerialization @@ -101,7 +102,7 @@ static inline bool is_jailbroken() { if (!systemVersion) { BSG_KSLOG_ERROR("Could not read SystemVersion.plist: %@", error); } - } + }); return systemVersion; } From 99cf659239b881b6c68d381ca73a4eac9a1e7241 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Tue, 30 Mar 2021 16:56:04 +0100 Subject: [PATCH 19/20] Support Mac Catalyst build --- Bugsnag.xcodeproj/project.pbxproj | 6 ++---- CHANGELOG.md | 3 +++ .../Bugsnag Test App.xcodeproj/project.pbxproj | 3 --- .../bugsnag-example.xcodeproj/project.pbxproj | 11 +++++++++-- .../bugsnag-example/bugsnag-example.entitlements | 10 ++++++++++ 5 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 examples/swift-ios/bugsnag-example/bugsnag-example.entitlements diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index fb0b930b1..6b9b82173 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -3323,6 +3323,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_MODULES_AUTOLINK = NO; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -3337,7 +3338,6 @@ ); MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap"; SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = NO; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -3346,6 +3346,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_MODULES_AUTOLINK = NO; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -3360,7 +3361,6 @@ ); MODULEMAP_FILE = "$(PROJECT_DIR)/Framework/module.modulemap"; SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = NO; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -3578,7 +3578,6 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.3; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = NO; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -3590,7 +3589,6 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.3; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = NO; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/CHANGELOG.md b/CHANGELOG.md index bd033a780..f8343e859 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ Changelog ### Bug fixes +* Enable `SUPPORTS_MACCATALYST` in main Xcode project. + [#1055](https://github.com/bugsnag/bugsnag-cocoa/pull/1055) + * `osName` and `osVersion` now reflect the Mac's OS when running Mac Catalyst apps or iOS apps running on macOS. Fix reporting of `model` for Mac Catalyst apps or iOS apps running on macOS. [#1054](https://github.com/bugsnag/bugsnag-cocoa/pull/1054) diff --git a/examples/objective-c-ios/Bugsnag Test App.xcodeproj/project.pbxproj b/examples/objective-c-ios/Bugsnag Test App.xcodeproj/project.pbxproj index 35f06d32e..7c3237475 100644 --- a/examples/objective-c-ios/Bugsnag Test App.xcodeproj/project.pbxproj +++ b/examples/objective-c-ios/Bugsnag Test App.xcodeproj/project.pbxproj @@ -313,7 +313,6 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; - DEPLOYMENT_POSTPROCESSING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -365,7 +364,6 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; - DEPLOYMENT_POSTPROCESSING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; @@ -397,7 +395,6 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; - DEPLOYMENT_POSTPROCESSING = YES; DEVELOPMENT_TEAM = 372ZUL2ZB7; ENABLE_BITCODE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; diff --git a/examples/swift-ios/bugsnag-example.xcodeproj/project.pbxproj b/examples/swift-ios/bugsnag-example.xcodeproj/project.pbxproj index 5a3e0b0b2..4dc454035 100644 --- a/examples/swift-ios/bugsnag-example.xcodeproj/project.pbxproj +++ b/examples/swift-ios/bugsnag-example.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ /* Begin PBXFileReference section */ 00C3ED5B23F2DA4900757DBD /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 015637022613754E004F6047 /* bugsnag-example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "bugsnag-example.entitlements"; sourceTree = ""; }; 3573BE2B7139FE81FC96415D /* Pods_bugsnag_example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_bugsnag_example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 378BA2CB24229CBB00123123 /* OutOfMemoryController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutOfMemoryController.h; sourceTree = ""; }; 378BA2CC24229CBB00123123 /* OutOfMemoryController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutOfMemoryController.m; sourceTree = ""; }; @@ -88,6 +89,7 @@ D175F4BA1ACDBD81009AFFB7 /* bugsnag-example */ = { isa = PBXGroup; children = ( + 015637022613754E004F6047 /* bugsnag-example.entitlements */, 379D2038242B697600C11EFE /* LaunchScreen.storyboard */, D175F4BD1ACDBD81009AFFB7 /* AppDelegate.swift */, D175F4BF1ACDBD81009AFFB7 /* ViewController.swift */, @@ -149,6 +151,7 @@ TargetAttributes = { D175F4B71ACDBD81009AFFB7 = { CreatedOnToolsVersion = 6.2; + DevelopmentTeam = 372ZUL2ZB7; LastSwiftMigration = 1010; }; }; @@ -383,10 +386,11 @@ baseConfigurationReference = C9204A923B81A3D14457E739 /* Pods-bugsnag-example.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "bugsnag-example/bugsnag-example.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 372ZUL2ZB7; INFOPLIST_FILE = "bugsnag-example/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -394,6 +398,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.bugsnag-example"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + SUPPORTS_MACCATALYST = YES; SWIFT_OBJC_BRIDGING_HEADER = "bugsnag-example/bugsnag-example-Bridging-Header.h"; SWIFT_VERSION = 4.2; }; @@ -404,10 +409,11 @@ baseConfigurationReference = C72198B7DFCD1FD2F92628E3 /* Pods-bugsnag-example.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = "bugsnag-example/bugsnag-example.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 372ZUL2ZB7; INFOPLIST_FILE = "bugsnag-example/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -415,6 +421,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.bugsnag.bugsnag-example"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + SUPPORTS_MACCATALYST = YES; SWIFT_OBJC_BRIDGING_HEADER = "bugsnag-example/bugsnag-example-Bridging-Header.h"; SWIFT_VERSION = 4.2; }; diff --git a/examples/swift-ios/bugsnag-example/bugsnag-example.entitlements b/examples/swift-ios/bugsnag-example/bugsnag-example.entitlements new file mode 100644 index 000000000..ee95ab7e5 --- /dev/null +++ b/examples/swift-ios/bugsnag-example/bugsnag-example.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + From 6be044b64f577a8801fb3392e513edc4423b0158 Mon Sep 17 00:00:00 2001 From: Nick Dowell Date: Wed, 31 Mar 2021 10:40:30 +0100 Subject: [PATCH 20/20] Release v6.8.2 --- .jazzy.yaml | 4 ++-- Bugsnag.podspec.json | 4 ++-- Bugsnag/Payload/BugsnagNotifier.m | 2 +- CHANGELOG.md | 6 +++--- Framework/Info.plist | 2 +- Tests/Info.plist | 2 +- VERSION | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.jazzy.yaml b/.jazzy.yaml index 45e833eb0..297e20bd1 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -2,11 +2,11 @@ author_url: "https://www.bugsnag.com" author: "Bugsnag Inc" clean: false # avoid deleting docs/.git framework_root: "Bugsnag" -github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.8.1/Bugsnag" +github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.8.2/Bugsnag" github_url: "https://github.com/bugsnag/bugsnag-cocoa" hide_documentation_coverage: true module: "Bugsnag" -module_version: "6.8.1" +module_version: "6.8.2" objc: true output: "docs" readme: "README.md" diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index 9f6e50f53..90b61b990 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -1,6 +1,6 @@ { "name": "Bugsnag", - "version": "6.8.1", + "version": "6.8.2", "summary": "The Bugsnag crash reporting framework for Apple platforms.", "homepage": "https://bugsnag.com", "license": "MIT", @@ -9,7 +9,7 @@ }, "source": { "git": "https://github.com/bugsnag/bugsnag-cocoa.git", - "tag": "v6.8.1" + "tag": "v6.8.2" }, "frameworks": [ "Foundation", diff --git a/Bugsnag/Payload/BugsnagNotifier.m b/Bugsnag/Payload/BugsnagNotifier.m index 605e29bcd..dc693e20a 100644 --- a/Bugsnag/Payload/BugsnagNotifier.m +++ b/Bugsnag/Payload/BugsnagNotifier.m @@ -23,7 +23,7 @@ - (instancetype)init { #else self.name = @"Bugsnag Objective-C"; #endif - self.version = @"6.8.1"; + self.version = @"6.8.2"; self.url = @"https://github.com/bugsnag/bugsnag-cocoa"; self.dependencies = [NSMutableArray new]; } diff --git a/CHANGELOG.md b/CHANGELOG.md index f8343e859..eca35d9a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,16 @@ Changelog ========= -## TBD +## 6.8.2 (2021-03-31) ### Bug fixes * Enable `SUPPORTS_MACCATALYST` in main Xcode project. - [#1055](https://github.com/bugsnag/bugsnag-cocoa/pull/1055) + [#1056](https://github.com/bugsnag/bugsnag-cocoa/pull/1056) * `osName` and `osVersion` now reflect the Mac's OS when running Mac Catalyst apps or iOS apps running on macOS. Fix reporting of `model` for Mac Catalyst apps or iOS apps running on macOS. - [#1054](https://github.com/bugsnag/bugsnag-cocoa/pull/1054) + [#1055](https://github.com/bugsnag/bugsnag-cocoa/pull/1055) * Uncaught exceptions thrown while handing UI events in iOS apps running on macOS are now detected. [#1053](https://github.com/bugsnag/bugsnag-cocoa/pull/1053) diff --git a/Framework/Info.plist b/Framework/Info.plist index f499e639e..ed265a98c 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.8.1 + 6.8.2 CFBundleVersion 1 diff --git a/Tests/Info.plist b/Tests/Info.plist index 6c6589925..b311bf9f7 100644 --- a/Tests/Info.plist +++ b/Tests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.8.1 + 6.8.2 CFBundleVersion 1 diff --git a/VERSION b/VERSION index 5f6c0863a..166d79d6d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.8.1 +6.8.2