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/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/CHANGELOG.md b/CHANGELOG.md index 9b5dca038..e6c67a603 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ Changelog ### 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)