diff --git a/.buildkite/pipeline.full.yml b/.buildkite/pipeline.full.yml index 11b6cd1b1..5acd11b43 100644 --- a/.buildkite/pipeline.full.yml +++ b/.buildkite/pipeline.full.yml @@ -95,6 +95,26 @@ steps: --tags='not @skip_macos' --fail-fast + - label: ':apple: macOS 10.13 full end-to-end tests' + depends_on: + - cocoa_fixture + timeout_in_minutes: 60 + agents: + queue: opensource-mac-cocoa-10.13 + plugins: + artifacts#v1.3.0: + download: ["features/fixtures/macos/output/macOSTestApp.zip"] + upload: ["macOSTestApp.log"] + commands: + - bundle install + - bundle exec maze-runner + --farm=local + --os=macos + --os-version=10.13 + --app=macOSTestApp + --tags='not @skip_macos' + --fail-fast + - label: ':apple: macOS 10.14 full end-to-end tests' depends_on: - cocoa_fixture diff --git a/.jazzy.yaml b/.jazzy.yaml index 297e20bd1..0ddce5756 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.2/Bugsnag" +github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.8.3/Bugsnag" github_url: "https://github.com/bugsnag/bugsnag-cocoa" hide_documentation_coverage: true module: "Bugsnag" -module_version: "6.8.2" +module_version: "6.8.3" objc: true output: "docs" readme: "README.md" diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index 90b61b990..0cfb5a91f 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -1,6 +1,6 @@ { "name": "Bugsnag", - "version": "6.8.2", + "version": "6.8.3", "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.2" + "tag": "v6.8.3" }, "frameworks": [ "Foundation", diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index a3b7963fb..9845271f1 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -953,7 +953,7 @@ - (void)notifyInternal:(BugsnagEvent *_Nonnull)event [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]; + [self.eventUploader uploadStoredEventsAfterDelay:1]; } else { [self.eventUploader uploadEvent:event completionHandler:nil]; } diff --git a/Bugsnag/Delivery/BSGEventUploadOperation.m b/Bugsnag/Delivery/BSGEventUploadOperation.m index 2205ac191..73af4a06d 100644 --- a/Bugsnag/Delivery/BSGEventUploadOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadOperation.m @@ -87,8 +87,16 @@ - (void)runWithDelegate:(id)delegate completion } } - NSDictionary *eventPayload = [event toJsonWithRedactedKeys:configuration.redactedKeys]; - + NSDictionary *eventPayload; + @try { + eventPayload = [event toJsonWithRedactedKeys:configuration.redactedKeys]; + } @catch (NSException *exception) { + bsg_log_err(@"Discarding event %@ because an exception was thrown by -toJsonWithRedactedKeys: %@", self.name, exception); + [self deleteEvent]; + completionHandler(); + return; + } + NSString *apiKey = event.apiKey ?: configuration.apiKey; NSMutableDictionary *requestPayload = [NSMutableDictionary dictionary]; diff --git a/Bugsnag/Delivery/BSGEventUploader.h b/Bugsnag/Delivery/BSGEventUploader.h index d6156e278..f41eb6703 100644 --- a/Bugsnag/Delivery/BSGEventUploader.h +++ b/Bugsnag/Delivery/BSGEventUploader.h @@ -25,6 +25,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)uploadStoredEvents; +- (void)uploadStoredEventsAfterDelay:(NSTimeInterval)delay; + - (void)uploadLatestStoredEvent:(void (^)(void))completionHandler; @end diff --git a/Bugsnag/Delivery/BSGEventUploader.m b/Bugsnag/Delivery/BSGEventUploader.m index 3e3ce2141..1a770893a 100644 --- a/Bugsnag/Delivery/BSGEventUploader.m +++ b/Bugsnag/Delivery/BSGEventUploader.m @@ -92,6 +92,13 @@ - (void)uploadStoredEvents { }]; } +- (void)uploadStoredEventsAfterDelay:(NSTimeInterval)delay { + dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{ + [self uploadStoredEvents]; + }); +} + - (void)uploadLatestStoredEvent:(void (^)(void))completionHandler { NSString *latestFile = [self sortedEventFiles].lastObject; BSGEventUploadFileOperation *operation = latestFile ? [self uploadOperationsWithFiles:@[latestFile]].lastObject : nil; diff --git a/Bugsnag/Helpers/BSGAppHangDetector.m b/Bugsnag/Helpers/BSGAppHangDetector.m index b12eb0fe1..9ef681f93 100644 --- a/Bugsnag/Helpers/BSGAppHangDetector.m +++ b/Bugsnag/Helpers/BSGAppHangDetector.m @@ -11,6 +11,7 @@ #import #import +#import "BSG_KSMach.h" #import "BugsnagLogger.h" #import "BugsnagThread+Recording.h" #import "BugsnagThread+Private.h" @@ -74,6 +75,12 @@ - (void)startWithDelegate:(id)delegate { dispatch_time_t timeout = dispatch_time(now, (int64_t)(threshold * NSEC_PER_SEC)); dispatch_after(after, backgroundQueue, ^{ if (dispatch_semaphore_wait(semaphore, timeout) != 0) { + if (bsg_ksmachisBeingTraced()) { + bsg_log_debug("Ignoring app hang because debugger is attached"); + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + return; + } + bsg_log_info("App hang detected"); NSArray *threads = nil; diff --git a/Bugsnag/Payload/BugsnagEvent.m b/Bugsnag/Payload/BugsnagEvent.m index 51af6c3bb..b423ab18d 100644 --- a/Bugsnag/Payload/BugsnagEvent.m +++ b/Bugsnag/Payload/BugsnagEvent.m @@ -563,7 +563,11 @@ - (NSDictionary *)toJsonWithRedactedKeys:(NSSet *)redactedKeys { // add metadata NSMutableDictionary *metadata = [[[self metadata] toDictionary] mutableCopy]; - event[BSGKeyMetadata] = [self sanitiseMetadata:metadata redactedKeys:redactedKeys]; + @try { + event[BSGKeyMetadata] = [self sanitiseMetadata:metadata redactedKeys:redactedKeys]; + } @catch (NSException *exception) { + bsg_log_err(@"An exception was thrown while sanitising metadata: %@", exception); + } event[BSGKeyDevice] = [self.device toDictionary]; event[BSGKeyApp] = [self.app toDict]; @@ -605,7 +609,15 @@ - (NSDictionary *)toJsonWithRedactedKeys:(NSSet *)redactedKeys { - (NSMutableDictionary *)sanitiseMetadata:(NSMutableDictionary *)metadata redactedKeys:(NSSet *)redactedKeys { for (NSString *sectionKey in [metadata allKeys]) { - metadata[sectionKey] = [metadata[sectionKey] mutableCopy]; + if ([metadata[sectionKey] isKindOfClass:[NSDictionary class]]) { + metadata[sectionKey] = [metadata[sectionKey] mutableCopy]; + } else { + NSString *message = [NSString stringWithFormat:@"Expected an NSDictionary but got %@ %@", + NSStringFromClass([metadata[sectionKey] class]), metadata[sectionKey]]; + bsg_log_err(@"%@", message); + // Leave an indication of the error in the payload for diagnosis + metadata[sectionKey] = [@{@"bugsnag.error": message} mutableCopy]; + } NSMutableDictionary *section = metadata[sectionKey]; if (section != nil) { // redact sensitive metadata values diff --git a/Bugsnag/Payload/BugsnagNotifier.m b/Bugsnag/Payload/BugsnagNotifier.m index dc693e20a..e6e99e6ba 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.2"; + self.version = @"6.8.3"; self.url = @"https://github.com/bugsnag/bugsnag-cocoa"; self.dependencies = [NSMutableArray new]; } diff --git a/CHANGELOG.md b/CHANGELOG.md index eca35d9a8..ba98f445d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ Changelog ========= +## 6.8.3 (2021-04-07) + +### Bug fixes + +* Catch exceptions thrown while preparing JSON for upload rather than crashing. + [#1063](https://github.com/bugsnag/bugsnag-cocoa/pull/1063) + +* Prevent app hangs being reported if a debugger is attached. + [#1058](https://github.com/bugsnag/bugsnag-cocoa/pull/1058) + ## 6.8.2 (2021-03-31) ### Bug fixes diff --git a/Framework/Info.plist b/Framework/Info.plist index ed265a98c..e2f60f814 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.8.2 + 6.8.3 CFBundleVersion 1 diff --git a/Tests/Info.plist b/Tests/Info.plist index b311bf9f7..ce261e1a0 100644 --- a/Tests/Info.plist +++ b/Tests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.8.2 + 6.8.3 CFBundleVersion 1 diff --git a/VERSION b/VERSION index 166d79d6d..021c9405b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.8.2 +6.8.3