Skip to content

Commit

Permalink
fix: Record NSException details immediately from C++ handler
Browse files Browse the repository at this point in the history
This avoids a case where if the NSException handler is overridden
without calling the previous handler, no report is recorded. In the case
that the handler is invoked twice for a given exception, it is only
recorded once by checking that the last recorded exception is the same.
  • Loading branch information
kattrali committed Sep 13, 2018
1 parent 3a68f27 commit 0c1c406
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 18 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

## TBD

### Bug Fixes

* Ensure NSException is captured when handler is overridden
[#313](https://github.com/bugsnag/bugsnag-cocoa/pull/313)

## 5.16.3 (14 Aug 2018)

### Bug Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@
#define likely_if(x) if (__builtin_expect(x, 1))
#define unlikely_if(x) if (__builtin_expect(x, 0))

#ifdef __cplusplus
extern "C" {
#endif
// Internal NSException recorder
void bsg_recordException(NSException *exception);
#ifdef __cplusplus
}
#endif

// ============================================================================
#pragma mark - Globals -
// ============================================================================
Expand Down Expand Up @@ -114,9 +123,11 @@ static void CPPExceptionTerminate(void) {
try {
throw;
} catch (NSException *exception) {
BSG_KSLOG_DEBUG(@"Detected NSException. Letting the current "
BSG_KSLOG_DEBUG(@"Detected NSException. Recording details "
@"and letting the current "
@"NSException handler deal with it.");
isNSException = true;
bsg_recordException(exception);
} catch (std::exception &exc) {
strncpy(descriptionBuff, exc.what(), sizeof(descriptionBuff));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,30 @@
/** Context to fill with crash information. */
static BSG_KSCrash_SentryContext *bsg_g_context;

static NSException *bsg_lastHandledException = NULL;

// ============================================================================
#pragma mark - Callbacks -
// ============================================================================

// Avoiding static methods due to linker issue.

/** Our custom excepetion handler.
* Fetch the stack trace from the exception and write a report.
*
* @param exception The exception that was raised.
/**
Capture exception details and write a new report. If the exception was
recorded before, no new report will be generated.
@param exception The exception to process
*/
void bsg_ksnsexc_i_handleException(NSException *exception) {
BSG_KSLOG_DEBUG(@"Trapped exception %@", exception);
void bsg_recordException(NSException *exception) {
if (bsg_g_installed) {
bool wasHandlingCrash = bsg_g_context->handlingCrash;
bsg_kscrashsentry_beginHandlingCrash(bsg_g_context);

BSG_KSLOG_DEBUG(
@"Exception handler is installed. Continuing exception handling.");

if (wasHandlingCrash) {
BSG_KSLOG_INFO(@"Detected crash in the crash reporter. Restoring "
@"original handlers.");
bsg_g_context->crashedDuringCrashHandling = true;
bsg_kscrashsentry_uninstall(BSG_KSCrashTypeAll);
BOOL previouslyHandled = exception == bsg_lastHandledException;
if (previouslyHandled) {
BSG_KSLOG_DEBUG(@"Handled exception previously, "
@"exiting exception recorder.");
return;
}
bsg_lastHandledException = exception;
BSG_KSLOG_DEBUG(@"Writing exception info into a new report");

BSG_KSLOG_DEBUG(@"Suspending all threads.");
bsg_kscrashsentry_suspendThreads();
Expand All @@ -95,6 +93,31 @@ void bsg_ksnsexc_i_handleException(NSException *exception) {

BSG_KSLOG_DEBUG(@"Calling main crash handler.");
bsg_g_context->onCrash();
}
}

/** Our custom excepetion handler.
* Fetch the stack trace from the exception and write a report.
*
* @param exception The exception that was raised.
*/
void bsg_ksnsexc_i_handleException(NSException *exception) {
BSG_KSLOG_DEBUG(@"Trapped exception %@", exception);
if (bsg_g_installed) {
bool wasHandlingCrash = bsg_g_context->handlingCrash;
bsg_kscrashsentry_beginHandlingCrash(bsg_g_context);

BSG_KSLOG_DEBUG(
@"Exception handler is installed. Continuing exception handling.");

if (wasHandlingCrash) {
BSG_KSLOG_INFO(@"Detected crash in the crash reporter. Restoring "
@"original handlers.");
bsg_g_context->crashedDuringCrashHandling = true;
bsg_kscrashsentry_uninstall(BSG_KSCrashTypeAll);
}

bsg_recordException(exception);

BSG_KSLOG_DEBUG(
@"Crash handling complete. Restoring original handlers.");
Expand Down

0 comments on commit 0c1c406

Please sign in to comment.