Added caught exception logging to PLCrashReporter (#277)

* Added caught exception logging to PLCrashReporter

Signed-off-by: Landon Fuller <landonf@plausible.coop>
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 <landonf@plausible.coop>
Co-authored-by: Ray Lillywhite <rayll@umich.edu>
Co-authored-by: Landon Fuller <landonf@plausible.coop>
This commit is contained in:
Jasmin Lapalme 2023-04-27 03:02:49 -04:00 коммит произвёл GitHub
Родитель a494faa23e
Коммит b6979c3c34
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 65 добавлений и 3 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -653,12 +653,31 @@ static PLCrashReporter *sharedReporter = nil;
*
* @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 {
@ -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
@ -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;
@ -713,6 +733,9 @@ static plcrash_error_t plcr_live_report_callback (plcrash_async_thread_state_t *
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;
@ -797,10 +820,14 @@ cleanup:
* @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.
*

Просмотреть файл

@ -46,6 +46,39 @@
#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.
*/