Skip to content

Commit 6c76f58

Browse files
authored
feat: inspect/enrich event in crashpad backend (#843)
1 parent 6011498 commit 6c76f58

File tree

2 files changed

+61
-50
lines changed

2 files changed

+61
-50
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
**Features**:
66

7-
- disable PC adjustment in the backend for libunwindstack ([#839](https://github.com/getsentry/sentry-native/pull/839))
7+
- Disable PC adjustment in the backend for libunwindstack ([#839](https://github.com/getsentry/sentry-native/pull/839))
8+
- Crashpad backend allows inspection and enrichment of the crash event in the on_crash/before_send hooks ([#843](https://github.com/getsentry/sentry-native/pull/843))
89

910
**Internal**:
1011

src/backends/sentry_backend_crashpad.cpp

Lines changed: 59 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -78,31 +78,37 @@ typedef struct {
7878
sentry_path_t *breadcrumb1_path;
7979
sentry_path_t *breadcrumb2_path;
8080
size_t num_breadcrumbs;
81+
sentry_value_t crash_event;
8182
} crashpad_state_t;
8283

8384
static void
84-
sentry__crashpad_backend_user_consent_changed(sentry_backend_t *backend)
85+
crashpad_backend_user_consent_changed(sentry_backend_t *backend)
8586
{
86-
crashpad_state_t *data = (crashpad_state_t *)backend->data;
87+
auto *data = static_cast<crashpad_state_t *>(backend->data);
8788
if (!data->db || !data->db->GetSettings()) {
8889
return;
8990
}
9091
data->db->GetSettings()->SetUploadsEnabled(!sentry__should_skip_upload());
9192
}
9293

9394
static void
94-
sentry__crashpad_backend_flush_scope(
95+
crashpad_backend_flush_scope(
9596
sentry_backend_t *backend, const sentry_options_t *options)
9697
{
97-
const crashpad_state_t *data = (crashpad_state_t *)backend->data;
98+
auto *data = static_cast<crashpad_state_t *>(backend->data);
9899
if (!data->event_path) {
99100
return;
100101
}
101102

102103
// This here is an empty object that we copy the scope into.
103104
// Even though the API is specific to `event`, an `event` has a few default
104-
// properties that we do not want here.
105-
sentry_value_t event = sentry_value_new_object();
105+
// properties that we do not want here. But in case of a crash we use the
106+
// crash-event filled in the crash-handler and on_crash/before_send
107+
// respectively.
108+
sentry_value_t event = sentry_value_is_null(data->crash_event)
109+
? sentry_value_new_object()
110+
: data->crash_event;
111+
106112
SENTRY_WITH_SCOPE (scope) {
107113
// we want the scope without any modules or breadcrumbs
108114
sentry__scope_apply_to_event(scope, options, event, SENTRY_SCOPE_NONE);
@@ -138,9 +144,11 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
138144
SENTRY_DEBUG("flushing session and queue before crashpad handler");
139145

140146
bool should_dump = true;
141-
sentry_value_t event = sentry_value_new_event();
142147

143148
SENTRY_WITH_OPTIONS (options) {
149+
auto *data = static_cast<crashpad_state_t *>(options->backend->data);
150+
sentry_value_decref(data->crash_event);
151+
data->crash_event = sentry_value_new_event();
144152

145153
if (options->on_crash_func) {
146154
sentry_ucontext_t uctx;
@@ -153,17 +161,18 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
153161
# endif
154162

155163
SENTRY_TRACE("invoking `on_crash` hook");
156-
event
157-
= options->on_crash_func(&uctx, event, options->on_crash_data);
164+
data->crash_event = options->on_crash_func(
165+
&uctx, data->crash_event, options->on_crash_data);
158166
} else if (options->before_send_func) {
159167
SENTRY_TRACE("invoking `before_send` hook");
160-
event = options->before_send_func(
161-
event, nullptr, options->before_send_data);
168+
data->crash_event = options->before_send_func(
169+
data->crash_event, nullptr, options->before_send_data);
162170
}
163-
should_dump = !sentry_value_is_null(event);
164-
sentry_value_decref(event);
171+
should_dump = !sentry_value_is_null(data->crash_event);
165172

166173
if (should_dump) {
174+
crashpad_backend_flush_scope(options->backend, options);
175+
167176
sentry__write_crash_marker(options);
168177

169178
sentry__record_errors_on_current_session(1);
@@ -231,10 +240,10 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
231240
#endif
232241

233242
static int
234-
sentry__crashpad_backend_startup(
243+
crashpad_backend_startup(
235244
sentry_backend_t *backend, const sentry_options_t *options)
236245
{
237-
sentry_path_t *owned_handler_path = NULL;
246+
sentry_path_t *owned_handler_path = nullptr;
238247
sentry_path_t *handler_path = options->handler_path;
239248
if (!handler_path) {
240249
sentry_path_t *current_exe = sentry__path_current_exe();
@@ -272,7 +281,7 @@ sentry__crashpad_backend_startup(
272281
"\"%" SENTRY_PATH_PRI "\"",
273282
absolute_handler_path->path);
274283
sentry_path_t *current_run_folder = options->run->run_path;
275-
crashpad_state_t *data = (crashpad_state_t *)backend->data;
284+
auto *data = static_cast<crashpad_state_t *>(backend->data);
276285

277286
base::FilePath database(options->database_path->path);
278287
base::FilePath handler(absolute_handler_path->path);
@@ -283,7 +292,7 @@ sentry__crashpad_backend_startup(
283292
// register attachments
284293
for (sentry_attachment_t *attachment = options->attachments; attachment;
285294
attachment = attachment->next) {
286-
attachments.push_back(base::FilePath(attachment->path->path));
295+
attachments.emplace_back(attachment->path->path);
287296
}
288297

289298
// and add the serialized event, and two rotating breadcrumb files
@@ -299,12 +308,12 @@ sentry__crashpad_backend_startup(
299308
sentry__path_touch(data->breadcrumb1_path);
300309
sentry__path_touch(data->breadcrumb2_path);
301310

302-
attachments.push_back(base::FilePath(data->event_path->path));
303-
attachments.push_back(base::FilePath(data->breadcrumb1_path->path));
304-
attachments.push_back(base::FilePath(data->breadcrumb2_path->path));
311+
attachments.insert(attachments.end(),
312+
{ base::FilePath(data->event_path->path),
313+
base::FilePath(data->breadcrumb1_path->path),
314+
base::FilePath(data->breadcrumb2_path->path) });
305315

306-
std::vector<std::string> arguments;
307-
arguments.push_back("--no-rate-limit");
316+
std::vector<std::string> arguments { "--no-rate-limit" };
308317

309318
// Initialize database first, flushing the consent later on as part of
310319
// `sentry_init` will persist the upload flag.
@@ -395,7 +404,7 @@ sentry__crashpad_backend_startup(
395404
}
396405

397406
static void
398-
sentry__crashpad_backend_shutdown(sentry_backend_t *backend)
407+
crashpad_backend_shutdown(sentry_backend_t *backend)
399408
{
400409
#ifdef SENTRY_PLATFORM_LINUX
401410
// restore signal handlers to their default state
@@ -406,7 +415,7 @@ sentry__crashpad_backend_shutdown(sentry_backend_t *backend)
406415
}
407416
#endif
408417

409-
crashpad_state_t *data = (crashpad_state_t *)backend->data;
418+
auto *data = static_cast<crashpad_state_t *>(backend->data);
410419
delete data->db;
411420
data->db = nullptr;
412421

@@ -419,10 +428,10 @@ sentry__crashpad_backend_shutdown(sentry_backend_t *backend)
419428
}
420429

421430
static void
422-
sentry__crashpad_backend_add_breadcrumb(sentry_backend_t *backend,
431+
crashpad_backend_add_breadcrumb(sentry_backend_t *backend,
423432
sentry_value_t breadcrumb, const sentry_options_t *options)
424433
{
425-
crashpad_state_t *data = (crashpad_state_t *)backend->data;
434+
auto *data = static_cast<crashpad_state_t *>(backend->data);
426435

427436
size_t max_breadcrumbs = options->max_breadcrumbs;
428437
if (!max_breadcrumbs) {
@@ -457,17 +466,18 @@ sentry__crashpad_backend_add_breadcrumb(sentry_backend_t *backend,
457466
}
458467

459468
static void
460-
sentry__crashpad_backend_free(sentry_backend_t *backend)
469+
crashpad_backend_free(sentry_backend_t *backend)
461470
{
462-
crashpad_state_t *data = (crashpad_state_t *)backend->data;
471+
auto *data = static_cast<crashpad_state_t *>(backend->data);
463472
sentry__path_free(data->event_path);
464473
sentry__path_free(data->breadcrumb1_path);
465474
sentry__path_free(data->breadcrumb2_path);
475+
sentry_value_decref(data->crash_event);
466476
sentry_free(data);
467477
}
468478

469479
static void
470-
sentry__crashpad_backend_except(
480+
crashpad_backend_except(
471481
sentry_backend_t *UNUSED(backend), const sentry_ucontext_t *context)
472482
{
473483
#ifdef SENTRY_PLATFORM_WINDOWS
@@ -486,7 +496,7 @@ report_crash_time(
486496
{
487497
// we do a `+ 1` here, because crashpad timestamps are second resolution,
488498
// but our sessions are ms resolution. at least in our integration tests, we
489-
// can have a session that starts at, eg. `0.471`, whereas the crashpad
499+
// can have a session that starts at, e.g. `0.471`, whereas the crashpad
490500
// report will be `0`, which would mean our heuristic does not trigger due
491501
// to rounding.
492502
uint64_t time = ((uint64_t)report.creation_time + 1) * 1000;
@@ -496,9 +506,9 @@ report_crash_time(
496506
}
497507

498508
static uint64_t
499-
sentry__crashpad_backend_last_crash(sentry_backend_t *backend)
509+
crashpad_backend_last_crash(sentry_backend_t *backend)
500510
{
501-
crashpad_state_t *data = (crashpad_state_t *)backend->data;
511+
auto *data = static_cast<crashpad_state_t *>(backend->data);
502512

503513
uint64_t crash_time = 0;
504514

@@ -514,9 +524,9 @@ sentry__crashpad_backend_last_crash(sentry_backend_t *backend)
514524
}
515525

516526
static void
517-
sentry__crashpad_backend_prune_database(sentry_backend_t *backend)
527+
crashpad_backend_prune_database(sentry_backend_t *backend)
518528
{
519-
crashpad_state_t *data = (crashpad_state_t *)backend->data;
529+
auto *data = static_cast<crashpad_state_t *>(backend->data);
520530

521531
// We want to eagerly clean up reports older than 2 days, and limit the
522532
// complete database to a maximum of 8M. That might still be a lot for
@@ -532,29 +542,29 @@ sentry__crashpad_backend_prune_database(sentry_backend_t *backend)
532542
sentry_backend_t *
533543
sentry__backend_new(void)
534544
{
535-
sentry_backend_t *backend = SENTRY_MAKE(sentry_backend_t);
545+
auto *backend = SENTRY_MAKE(sentry_backend_t);
536546
if (!backend) {
537-
return NULL;
547+
return nullptr;
538548
}
539549
memset(backend, 0, sizeof(sentry_backend_t));
540550

541-
crashpad_state_t *data = SENTRY_MAKE(crashpad_state_t);
551+
auto *data = SENTRY_MAKE(crashpad_state_t);
542552
if (!data) {
543553
sentry_free(backend);
544-
return NULL;
554+
return nullptr;
545555
}
546556
memset(data, 0, sizeof(crashpad_state_t));
547-
548-
backend->startup_func = sentry__crashpad_backend_startup;
549-
backend->shutdown_func = sentry__crashpad_backend_shutdown;
550-
backend->except_func = sentry__crashpad_backend_except;
551-
backend->free_func = sentry__crashpad_backend_free;
552-
backend->flush_scope_func = sentry__crashpad_backend_flush_scope;
553-
backend->add_breadcrumb_func = sentry__crashpad_backend_add_breadcrumb;
554-
backend->user_consent_changed_func
555-
= sentry__crashpad_backend_user_consent_changed;
556-
backend->get_last_crash_func = sentry__crashpad_backend_last_crash;
557-
backend->prune_database_func = sentry__crashpad_backend_prune_database;
557+
data->crash_event = sentry_value_new_null();
558+
559+
backend->startup_func = crashpad_backend_startup;
560+
backend->shutdown_func = crashpad_backend_shutdown;
561+
backend->except_func = crashpad_backend_except;
562+
backend->free_func = crashpad_backend_free;
563+
backend->flush_scope_func = crashpad_backend_flush_scope;
564+
backend->add_breadcrumb_func = crashpad_backend_add_breadcrumb;
565+
backend->user_consent_changed_func = crashpad_backend_user_consent_changed;
566+
backend->get_last_crash_func = crashpad_backend_last_crash;
567+
backend->prune_database_func = crashpad_backend_prune_database;
558568
backend->data = data;
559569
backend->can_capture_after_shutdown = true;
560570

0 commit comments

Comments
 (0)