Guard PLCR initialization with dispatch_once instead of try/catch

PLCrashReporter may only be initialized once. So make sure the developer can't break this
This commit is contained in:
Andreas Linde 2013-08-17 15:36:20 +02:00
parent 22dd9006ab
commit 88627a48b4

View File

@ -528,52 +528,51 @@ NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus";
if (!_isSetup) { if (!_isSetup) {
BITPLCrashReporter *crashReporter = [BITPLCrashReporter sharedReporter]; BITPLCrashReporter *crashReporter = [BITPLCrashReporter sharedReporter];
NSError *error = NULL;
// Check if we previously crashed // Check if we previously crashed
if ([crashReporter hasPendingCrashReport]) { if ([crashReporter hasPendingCrashReport]) {
_didCrashInLastSession = YES; _didCrashInLastSession = YES;
[self handleCrashReport]; [self handleCrashReport];
} }
// PLCrashReporter is throwing an NSException if it is being enabled again // Multiple exception handlers can be set, but we can only query the top level error handler (uncaught exception handler).
// even though it already is enabled //
@try { // To check if PLCrashReporter's error handler is successfully added, we compare the top
// Multiple exception handlers can be set, but we can only query the top level error handler (uncaught exception handler). // level one that is set before and the one after PLCrashReporter sets up its own.
// //
// To check if PLCrashReporter's error handler is successfully added, we compare the top // With delayed processing we can then check if another error handler was set up afterwards
// level one that is set before and the one after PLCrashReporter sets up its own. // and can show a debug warning log message, that the dev has to make sure the "newer" error handler
// // doesn't exit the process itself, because then all subsequent handlers would never be invoked.
// With delayed processing we can then check if another error handler was set up afterwards //
// and can show a debug warning log message, that the dev has to make sure the "newer" error handler // Note: ANY error handler setup BEFORE HockeySDK initialization will not be processed!
// doesn't exit the process itself, because then all subsequent handlers would never be invoked.
// // get the current top level error handler
// Note: ANY error handler setup BEFORE HockeySDK initialization will not be processed! NSUncaughtExceptionHandler *initialHandler = NSGetUncaughtExceptionHandler();
// get the current top level error handler // PLCrashReporter may only be initialized once. So make sure the developer
NSUncaughtExceptionHandler *initialHandler = NSGetUncaughtExceptionHandler(); // can't break this
static dispatch_once_t plcrPredicate;
dispatch_once(&plcrPredicate, ^{
NSError *error = NULL;
// Enable the Crash Reporter // Enable the Crash Reporter
if (![crashReporter enableCrashReporterAndReturnError: &error]) if (![crashReporter enableCrashReporterAndReturnError: &error])
NSLog(@"[HockeySDK] WARNING: Could not enable crash reporter: %@", [error localizedDescription]); NSLog(@"[HockeySDK] WARNING: Could not enable crash reporter: %@", [error localizedDescription]);
});
// get the new current top level error handler, which should now be the one from PLCrashReporter
NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler(); // get the new current top level error handler, which should now be the one from PLCrashReporter
NSUncaughtExceptionHandler *currentHandler = NSGetUncaughtExceptionHandler();
// do we have a new top level error handler? then we were successful
if (currentHandler && currentHandler != initialHandler) {
_exceptionHandler = currentHandler;
// do we have a new top level error handler? then we were successful BITHockeyLog(@"INFO: Exception handler successfully initialized.");
if (currentHandler && currentHandler != initialHandler) { } else {
_exceptionHandler = currentHandler; // this should never happen, theoretically only if NSSetUncaugtExceptionHandler() has some internal issues
NSLog(@"[HockeySDK] ERROR: Exception handler could not be set. Make sure there is no other exception handler set up!");
BITHockeyLog(@"INFO: Exception handler successfully initialized.");
} else {
// this should never happen, theoretically only if NSSetUncaugtExceptionHandler() has some internal issues
NSLog(@"[HockeySDK] ERROR: Exception handler could not be set. Make sure there is no other exception handler set up!");
}
} }
@catch (NSException * e) {
NSLog(@"[HockeySDK] WARNING: %@", [e reason]);
}
_isSetup = YES; _isSetup = YES;
} }