@@ -19,6 +19,7 @@ extern "C" {
1919# include " sentry_unix_pageallocator.h"
2020#endif
2121#include " sentry_utils.h"
22+ #include " sentry_uuid.h"
2223#include " transports/sentry_disk_transport.h"
2324}
2425
@@ -114,9 +115,11 @@ typedef struct {
114115 sentry_path_t *event_path;
115116 sentry_path_t *breadcrumb1_path;
116117 sentry_path_t *breadcrumb2_path;
118+ sentry_path_t *feedback_path;
117119 size_t num_breadcrumbs;
118120 std::atomic<bool > crashed;
119121 std::atomic<bool > scope_flush;
122+ sentry_uuid_t crash_event_id;
120123} crashpad_state_t ;
121124
122125/* *
@@ -185,7 +188,7 @@ crashpad_register_wer_module(
185188#endif
186189
187190static void
188- crashpad_backend_flush_scope_to_event (const sentry_path_t *event_path,
191+ flush_scope_to_event (const sentry_path_t *event_path,
189192 const sentry_options_t *options, sentry_value_t crash_event)
190193{
191194 SENTRY_WITH_SCOPE (scope) {
@@ -196,7 +199,6 @@ crashpad_backend_flush_scope_to_event(const sentry_path_t *event_path,
196199
197200 size_t mpack_size;
198201 char *mpack = sentry_value_to_msgpack (crash_event, &mpack_size);
199- sentry_value_decref (crash_event);
200202 if (!mpack) {
201203 return ;
202204 }
@@ -209,6 +211,26 @@ crashpad_backend_flush_scope_to_event(const sentry_path_t *event_path,
209211 }
210212}
211213
214+ static void
215+ flush_scope_to_feedback (const sentry_path_t *event_path,
216+ const sentry_options_t *options, sentry_value_t crash_event)
217+ {
218+ sentry_envelope_t *envelope = sentry__envelope_new ();
219+ if (!envelope) {
220+ return ;
221+ }
222+ sentry__envelope_add_event (envelope, crash_event);
223+ if (options->session ) {
224+ sentry__envelope_add_session (envelope, options->session );
225+ }
226+
227+ if (sentry__path_create_dir_all (options->run ->feedback_path ) != 0
228+ || sentry_envelope_write_to_path (envelope, event_path) != 0 ) {
229+ SENTRY_WARN (" flushing scope to feedback failed" );
230+ }
231+ sentry_envelope_free (envelope);
232+ }
233+
212234// This function is necessary for macOS since it has no `FirstChanceHandler`.
213235// but it is also necessary on Windows if the WER handler is enabled.
214236// This means we have to continuously flush the scope on
@@ -234,12 +256,19 @@ crashpad_backend_flush_scope(
234256 }
235257
236258 sentry_value_t event = sentry_value_new_object ();
259+ sentry_value_set_by_key (
260+ event, " event_id" , sentry__value_new_uuid (&data->crash_event_id ));
237261 // Since this will only be uploaded in case of a crash we must make this
238262 // event fatal.
239263 sentry_value_set_by_key (
240264 event, " level" , sentry__value_new_level (SENTRY_LEVEL_FATAL));
241265
242- crashpad_backend_flush_scope_to_event (data->event_path , options, event);
266+ flush_scope_to_event (data->event_path , options, event);
267+ if (data->feedback_path ) {
268+ flush_scope_to_feedback (data->feedback_path , options, event);
269+ } else {
270+ sentry_value_decref (event);
271+ }
243272 data->scope_flush .store (false , std::memory_order_release);
244273#endif
245274}
@@ -262,8 +291,12 @@ flush_scope_from_handler(
262291 }
263292
264293 // now we are the sole flusher and can flush into the crash event
265- crashpad_backend_flush_scope_to_event (
266- state->event_path , options, crash_event);
294+ flush_scope_to_event (state->event_path , options, crash_event);
295+ if (state->feedback_path ) {
296+ flush_scope_to_feedback (state->feedback_path , options, crash_event);
297+ } else {
298+ sentry_value_decref (crash_event);
299+ }
267300}
268301
269302# ifdef SENTRY_PLATFORM_WINDOWS
@@ -281,7 +314,9 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
281314 bool should_dump = true ;
282315
283316 SENTRY_WITH_OPTIONS (options) {
284- sentry_value_t crash_event = sentry_value_new_event ();
317+ auto state = static_cast <crashpad_state_t *>(options->backend ->data );
318+ sentry_value_t crash_event
319+ = sentry__value_new_event_with_uuid (&state->crash_event_id );
285320 sentry_value_set_by_key (
286321 crash_event, " level" , sentry__value_new_level (SENTRY_LEVEL_FATAL));
287322
@@ -418,6 +453,9 @@ crashpad_backend_startup(
418453 sentry_path_t *current_run_folder = options->run ->run_path ;
419454 auto *data = static_cast <crashpad_state_t *>(backend->data );
420455
456+ // prepare a predictable event ID for a potential future crash
457+ data->crash_event_id = sentry__new_event_id ();
458+
421459 base::FilePath database (options->database_path ->path );
422460 base::FilePath handler (absolute_handler_path->path );
423461
@@ -455,6 +493,19 @@ crashpad_backend_startup(
455493 sentry__path_free (screenshot_path);
456494 }
457495
496+ base::FilePath feedback_handler;
497+ base::FilePath feedback_path;
498+ if (options->feedback_handler_path ) {
499+ char *filename
500+ = sentry__uuid_as_filename (&data->crash_event_id , " .envelope" );
501+ data->feedback_path
502+ = sentry__path_join_str (options->run ->feedback_path , filename);
503+ sentry_free (filename);
504+
505+ feedback_handler = base::FilePath (options->feedback_handler_path ->path );
506+ feedback_path = base::FilePath (data->feedback_path ->path );
507+ }
508+
458509 std::vector<std::string> arguments { " --no-rate-limit" };
459510
460511 // Initialize database first, flushing the consent later on as part of
@@ -482,7 +533,7 @@ crashpad_backend_startup(
482533 minidump_url ? minidump_url : " " , proxy_url, annotations, arguments,
483534 /* restartable */ true ,
484535 /* asynchronous_start */ false , attachments, screenshot,
485- options->crashpad_wait_for_upload );
536+ options->crashpad_wait_for_upload , feedback_handler, feedback_path );
486537 sentry_free (minidump_url);
487538
488539#ifdef SENTRY_PLATFORM_WINDOWS
@@ -595,6 +646,7 @@ crashpad_backend_free(sentry_backend_t *backend)
595646 sentry__path_free (data->event_path );
596647 sentry__path_free (data->breadcrumb1_path );
597648 sentry__path_free (data->breadcrumb2_path );
649+ sentry__path_free (data->feedback_path );
598650 sentry_free (data);
599651}
600652
0 commit comments