Skip to content

Commit

Permalink
feat: inspect/enrich event in crashpad backend (#843)
Browse files Browse the repository at this point in the history
  • Loading branch information
supervacuus authored May 16, 2023
1 parent 6011498 commit 6c76f58
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 50 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

**Features**:

- disable PC adjustment in the backend for libunwindstack ([#839](https://github.com/getsentry/sentry-native/pull/839))
- Disable PC adjustment in the backend for libunwindstack ([#839](https://github.com/getsentry/sentry-native/pull/839))
- 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))

**Internal**:

Expand Down
108 changes: 59 additions & 49 deletions src/backends/sentry_backend_crashpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,37 @@ typedef struct {
sentry_path_t *breadcrumb1_path;
sentry_path_t *breadcrumb2_path;
size_t num_breadcrumbs;
sentry_value_t crash_event;
} crashpad_state_t;

static void
sentry__crashpad_backend_user_consent_changed(sentry_backend_t *backend)
crashpad_backend_user_consent_changed(sentry_backend_t *backend)
{
crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);
if (!data->db || !data->db->GetSettings()) {
return;
}
data->db->GetSettings()->SetUploadsEnabled(!sentry__should_skip_upload());
}

static void
sentry__crashpad_backend_flush_scope(
crashpad_backend_flush_scope(
sentry_backend_t *backend, const sentry_options_t *options)
{
const crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);
if (!data->event_path) {
return;
}

// This here is an empty object that we copy the scope into.
// Even though the API is specific to `event`, an `event` has a few default
// properties that we do not want here.
sentry_value_t event = sentry_value_new_object();
// properties that we do not want here. But in case of a crash we use the
// crash-event filled in the crash-handler and on_crash/before_send
// respectively.
sentry_value_t event = sentry_value_is_null(data->crash_event)
? sentry_value_new_object()
: data->crash_event;

SENTRY_WITH_SCOPE (scope) {
// we want the scope without any modules or breadcrumbs
sentry__scope_apply_to_event(scope, options, event, SENTRY_SCOPE_NONE);
Expand Down Expand Up @@ -138,9 +144,11 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
SENTRY_DEBUG("flushing session and queue before crashpad handler");

bool should_dump = true;
sentry_value_t event = sentry_value_new_event();

SENTRY_WITH_OPTIONS (options) {
auto *data = static_cast<crashpad_state_t *>(options->backend->data);
sentry_value_decref(data->crash_event);
data->crash_event = sentry_value_new_event();

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

SENTRY_TRACE("invoking `on_crash` hook");
event
= options->on_crash_func(&uctx, event, options->on_crash_data);
data->crash_event = options->on_crash_func(
&uctx, data->crash_event, options->on_crash_data);
} else if (options->before_send_func) {
SENTRY_TRACE("invoking `before_send` hook");
event = options->before_send_func(
event, nullptr, options->before_send_data);
data->crash_event = options->before_send_func(
data->crash_event, nullptr, options->before_send_data);
}
should_dump = !sentry_value_is_null(event);
sentry_value_decref(event);
should_dump = !sentry_value_is_null(data->crash_event);

if (should_dump) {
crashpad_backend_flush_scope(options->backend, options);

sentry__write_crash_marker(options);

sentry__record_errors_on_current_session(1);
Expand Down Expand Up @@ -231,10 +240,10 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
#endif

static int
sentry__crashpad_backend_startup(
crashpad_backend_startup(
sentry_backend_t *backend, const sentry_options_t *options)
{
sentry_path_t *owned_handler_path = NULL;
sentry_path_t *owned_handler_path = nullptr;
sentry_path_t *handler_path = options->handler_path;
if (!handler_path) {
sentry_path_t *current_exe = sentry__path_current_exe();
Expand Down Expand Up @@ -272,7 +281,7 @@ sentry__crashpad_backend_startup(
"\"%" SENTRY_PATH_PRI "\"",
absolute_handler_path->path);
sentry_path_t *current_run_folder = options->run->run_path;
crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);

base::FilePath database(options->database_path->path);
base::FilePath handler(absolute_handler_path->path);
Expand All @@ -283,7 +292,7 @@ sentry__crashpad_backend_startup(
// register attachments
for (sentry_attachment_t *attachment = options->attachments; attachment;
attachment = attachment->next) {
attachments.push_back(base::FilePath(attachment->path->path));
attachments.emplace_back(attachment->path->path);
}

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

attachments.push_back(base::FilePath(data->event_path->path));
attachments.push_back(base::FilePath(data->breadcrumb1_path->path));
attachments.push_back(base::FilePath(data->breadcrumb2_path->path));
attachments.insert(attachments.end(),
{ base::FilePath(data->event_path->path),
base::FilePath(data->breadcrumb1_path->path),
base::FilePath(data->breadcrumb2_path->path) });

std::vector<std::string> arguments;
arguments.push_back("--no-rate-limit");
std::vector<std::string> arguments { "--no-rate-limit" };

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

static void
sentry__crashpad_backend_shutdown(sentry_backend_t *backend)
crashpad_backend_shutdown(sentry_backend_t *backend)
{
#ifdef SENTRY_PLATFORM_LINUX
// restore signal handlers to their default state
Expand All @@ -406,7 +415,7 @@ sentry__crashpad_backend_shutdown(sentry_backend_t *backend)
}
#endif

crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);
delete data->db;
data->db = nullptr;

Expand All @@ -419,10 +428,10 @@ sentry__crashpad_backend_shutdown(sentry_backend_t *backend)
}

static void
sentry__crashpad_backend_add_breadcrumb(sentry_backend_t *backend,
crashpad_backend_add_breadcrumb(sentry_backend_t *backend,
sentry_value_t breadcrumb, const sentry_options_t *options)
{
crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);

size_t max_breadcrumbs = options->max_breadcrumbs;
if (!max_breadcrumbs) {
Expand Down Expand Up @@ -457,17 +466,18 @@ sentry__crashpad_backend_add_breadcrumb(sentry_backend_t *backend,
}

static void
sentry__crashpad_backend_free(sentry_backend_t *backend)
crashpad_backend_free(sentry_backend_t *backend)
{
crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);
sentry__path_free(data->event_path);
sentry__path_free(data->breadcrumb1_path);
sentry__path_free(data->breadcrumb2_path);
sentry_value_decref(data->crash_event);
sentry_free(data);
}

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

static uint64_t
sentry__crashpad_backend_last_crash(sentry_backend_t *backend)
crashpad_backend_last_crash(sentry_backend_t *backend)
{
crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);

uint64_t crash_time = 0;

Expand All @@ -514,9 +524,9 @@ sentry__crashpad_backend_last_crash(sentry_backend_t *backend)
}

static void
sentry__crashpad_backend_prune_database(sentry_backend_t *backend)
crashpad_backend_prune_database(sentry_backend_t *backend)
{
crashpad_state_t *data = (crashpad_state_t *)backend->data;
auto *data = static_cast<crashpad_state_t *>(backend->data);

// We want to eagerly clean up reports older than 2 days, and limit the
// complete database to a maximum of 8M. That might still be a lot for
Expand All @@ -532,29 +542,29 @@ sentry__crashpad_backend_prune_database(sentry_backend_t *backend)
sentry_backend_t *
sentry__backend_new(void)
{
sentry_backend_t *backend = SENTRY_MAKE(sentry_backend_t);
auto *backend = SENTRY_MAKE(sentry_backend_t);
if (!backend) {
return NULL;
return nullptr;
}
memset(backend, 0, sizeof(sentry_backend_t));

crashpad_state_t *data = SENTRY_MAKE(crashpad_state_t);
auto *data = SENTRY_MAKE(crashpad_state_t);
if (!data) {
sentry_free(backend);
return NULL;
return nullptr;
}
memset(data, 0, sizeof(crashpad_state_t));

backend->startup_func = sentry__crashpad_backend_startup;
backend->shutdown_func = sentry__crashpad_backend_shutdown;
backend->except_func = sentry__crashpad_backend_except;
backend->free_func = sentry__crashpad_backend_free;
backend->flush_scope_func = sentry__crashpad_backend_flush_scope;
backend->add_breadcrumb_func = sentry__crashpad_backend_add_breadcrumb;
backend->user_consent_changed_func
= sentry__crashpad_backend_user_consent_changed;
backend->get_last_crash_func = sentry__crashpad_backend_last_crash;
backend->prune_database_func = sentry__crashpad_backend_prune_database;
data->crash_event = sentry_value_new_null();

backend->startup_func = crashpad_backend_startup;
backend->shutdown_func = crashpad_backend_shutdown;
backend->except_func = crashpad_backend_except;
backend->free_func = crashpad_backend_free;
backend->flush_scope_func = crashpad_backend_flush_scope;
backend->add_breadcrumb_func = crashpad_backend_add_breadcrumb;
backend->user_consent_changed_func = crashpad_backend_user_consent_changed;
backend->get_last_crash_func = crashpad_backend_last_crash;
backend->prune_database_func = crashpad_backend_prune_database;
backend->data = data;
backend->can_capture_after_shutdown = true;

Expand Down

0 comments on commit 6c76f58

Please sign in to comment.