Skip to content

Commit

Permalink
Added caught exception logging to PLCrashReporter (#277)
Browse files Browse the repository at this point in the history
* Added caught exception logging to PLCrashReporter

Signed-off-by: Landon Fuller <[email protected]>
Issue: PLCR-459

* Add documentation and tests for the new live report generation functions.

Issue: PLCR-459

* Remove the use of autorelease

---------

Signed-off-by: Landon Fuller <[email protected]>
Co-authored-by: Ray Lillywhite <[email protected]>
Co-authored-by: Landon Fuller <[email protected]>
  • Loading branch information
3 people authored Apr 27, 2023
1 parent a494faa commit b6979c3
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Source/PLCrashReporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ typedef struct PLCrashReporterCallbacks {

- (NSData *) generateLiveReportWithThread: (thread_t) thread;
- (NSData *) generateLiveReportWithThread: (thread_t) thread error: (NSError **) outError;
- (NSData *) generateLiveReportWithThread: (thread_t) thread exception: (NSException *) exception error: (NSError **) outError;

- (NSData *) generateLiveReport;
- (NSData *) generateLiveReportAndReturnError: (NSError **) outError;
- (NSData *) generateLiveReportWithException: (NSException *) exception error: (NSError **) outError;

- (BOOL) purgePendingCrashReport;
- (BOOL) purgePendingCrashReportAndReturnError: (NSError **) outError;
Expand Down
33 changes: 30 additions & 3 deletions Source/PLCrashReporter.m
Original file line number Diff line number Diff line change
Expand Up @@ -653,12 +653,31 @@ - (BOOL) enableCrashReporterAndReturnError: (NSError **) outError {
*
* @return Returns nil if the crash report data could not be generated.
*
* @sa PLCrashReporter::generateLiveReportWithMachThread:error:
* @sa PLCrashReporter::generateLiveReportWithThread:exception:error:
*/
- (NSData *) generateLiveReportWithThread: (thread_t) thread {
return [self generateLiveReportWithThread: thread error: NULL];
}

/**
* Generate a live crash report for a given @a thread, without triggering an actual crash condition.
* This may be used to log current process state without actually crashing. The crash report data will be
* returned on success.
*
* @param thread The thread which will be marked as the failing thread in the generated report.
* @param outError A pointer to an NSError object variable. If an error occurs, this pointer
* will contain an error object indicating why the crash report could not be generated or loaded. If no
* error occurs, this parameter will be left unmodified. You may specify nil for this parameter, and no
* error information will be provided.
*
* @return Returns nil if the crash report data could not be loaded.
*
* @sa PLCrashReporter::generateLiveReportWithThread:exception:error:
*/
- (NSData *) generateLiveReportWithThread: (thread_t) thread error: (NSError **) outError {
return [self generateLiveReportWithThread: thread exception: nil error: outError];
}


/* State and callback used by -generateLiveReportWithThread */
struct plcr_live_report_context {
Expand All @@ -678,6 +697,7 @@ static plcrash_error_t plcr_live_report_callback (plcrash_async_thread_state_t *
* returned on success.
*
* @param thread The thread which will be marked as the failing thread in the generated report.
* @param exception An exception to be included as the report's uncaught exception, or nil.
* @param outError A pointer to an NSError object variable. If an error occurs, this pointer
* will contain an error object indicating why the crash report could not be generated or loaded. If no
* error occurs, this parameter will be left unmodified. You may specify nil for this parameter, and no
Expand All @@ -687,7 +707,7 @@ static plcrash_error_t plcr_live_report_callback (plcrash_async_thread_state_t *
*
* @todo Implement in-memory, rather than requiring writing of the report to disk.
*/
- (NSData *) generateLiveReportWithThread: (thread_t) thread error: (NSError **) outError {
- (NSData *) generateLiveReportWithThread: (thread_t) thread exception: (NSException *) exception error: (NSError **) outError {
plcrash_log_writer_t writer;
plcrash_async_file_t file;
plcrash_error_t err;
Expand All @@ -713,6 +733,9 @@ - (NSData *) generateLiveReportWithThread: (thread_t) thread error: (NSError **)
plcrash_log_writer_set_custom_data(&writer, self.customData);
}

if (exception != nil)
plcrash_log_writer_set_exception(&writer, exception);

/* Mock up a SIGTRAP-based signal info */
plcrash_log_bsd_signal_info_t bsd_signal_info;
plcrash_log_signal_info_t signal_info;
Expand Down Expand Up @@ -797,10 +820,14 @@ - (NSData *) generateLiveReport {
* @return Returns nil if the crash report data could not be loaded.
*/
- (NSData *) generateLiveReportAndReturnError: (NSError **) outError {
return [self generateLiveReportWithThread: pl_mach_thread_self() error: outError];
return [self generateLiveReportWithException: nil error: outError];
}


- (NSData *) generateLiveReportWithException: (NSException *)exception error: (NSError **) outError {
return [self generateLiveReportWithThread: pl_mach_thread_self() exception: exception error: outError];
}

/**
* Set the callbacks that will be executed by the receiver after a crash has occured and been recorded by PLCrashReporter.
*
Expand Down
33 changes: 33 additions & 0 deletions Tests/PLCrashReporterTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,39 @@ - (void) testSingleton {
#pragma clang diagnostic pop
}

/**
* Test generation of a 'live' crash report with a provided exception.
*/
- (void) testGenerateLiveReportWithException {
NSError *error;
NSData *reportData;
plcrash_test_thread_t thr;

/* Spawn a thread and generate a report for it */
plcrash_test_thread_spawn(&thr);

NSException *exc = [NSException exceptionWithName: NSInvalidArgumentException reason: @"Testing" userInfo: nil];
PLCrashReporter *reporter = [[PLCrashReporter alloc] initWithConfiguration: [PLCrashReporterConfig defaultConfiguration]];
reportData = [reporter generateLiveReportWithThread: pthread_mach_thread_np(thr.thread)
exception: exc
error: &error];
plcrash_test_thread_stop(&thr);
STAssertNotNil(reportData, @"Failed to generate live report: %@", error);

/* Try parsing the result */
PLCrashReport *report = [[PLCrashReport alloc] initWithData: reportData error: &error];
STAssertNotNil(report, @"Could not parse geneated live report: %@", error);

/* Sanity check the signal info */
STAssertEqualStrings([[report signalInfo] name], @"SIGTRAP", @"Incorrect signal name");
STAssertEqualStrings([[report signalInfo] code], @"TRAP_TRACE", @"Incorrect signal code");

/* Sanity check the exception info */
STAssertNotNil(report.exceptionInfo, @"Missing exception info");
STAssertEqualStrings(report.exceptionInfo.exceptionName, exc.name, @"Incorrect exception name");
STAssertEqualStrings(report.exceptionInfo.exceptionReason, exc.reason, @"Incorrect exception reason");
}

/**
* Test generation of a 'live' crash report for a specific thread.
*/
Expand Down

0 comments on commit b6979c3

Please sign in to comment.