diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index 70cbdf6308..7133fa2f19 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -148,6 +148,7 @@ typedef struct { std::atomic crashed; std::atomic scope_flush; sentry_uuid_t crash_event_id; + sentry_scope_observer_t *scope_observer; } crashpad_state_t; static void crashpad_backend_add_breadcrumb(sentry_backend_t *backend, @@ -880,6 +881,99 @@ process_completed_reports( } } +#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \ + || defined(SENTRY_PLATFORM_MACOS) +static sentry_path_t * +make_attachment_path(const sentry_path_t *run_path, sentry_value_t attachment) +{ + if (!sentry__attachment_get_bytes(attachment, nullptr)) { + return sentry__attachment_make_path(attachment); + } + + sentry_uuid_t id = sentry__attachment_get_id(attachment); + const char *filename = sentry__attachment_get_filename(attachment); + if (!run_path || sentry_uuid_is_nil(&id) + || sentry__string_empty(filename)) { + return nullptr; + } + + char uuid[37]; + sentry_uuid_as_string(&id, uuid); + sentry_path_t *dir = sentry__path_join_str(run_path, uuid); + sentry_path_t *path = dir ? sentry__path_join_str(dir, filename) : nullptr; + sentry_path_t *parent = path ? sentry__path_dir(path) : nullptr; + bool valid = parent && sentry__path_eq(parent, dir); + sentry__path_free(parent); + sentry__path_free(dir); + if (!valid) { + sentry__path_free(path); + return nullptr; + } + return path; +} + +static void +add_attachment(void *state, sentry_value_t attachment) +{ + auto *data = static_cast(state); + if (!data || !data->client) { + return; + } + + size_t bytes_len = 0; + const char *bytes = sentry__attachment_get_bytes(attachment, &bytes_len); + sentry_path_t *path = make_attachment_path(data->run_path, attachment); + if (!path) { + const char *filename = sentry__attachment_get_filename(attachment); + SENTRY_WARNF("failed to create path for crashpad attachment \"%s\"", + filename ? filename : ""); + return; + } + + if (bytes) { + sentry_path_t *dir = sentry__path_dir(path); + int rv = dir ? sentry__path_create_dir_all(dir) : 1; + sentry__path_free(dir); + if (rv != 0 || sentry__path_write_buffer(path, bytes, bytes_len) != 0) { + SENTRY_WARNF( + "failed to write crashpad attachment \"%s\"", path->path); + sentry__path_remove(path); + sentry__path_free(path); + return; + } + } + data->client->AddAttachment(base::FilePath(SENTRY_PATH_PLATFORM_STR(path))); + sentry__path_free(path); +} + +static void +remove_attachment(void *state, sentry_value_t attachment) +{ + auto *data = static_cast(state); + if (!data || !data->client) { + return; + } + sentry_path_t *path = make_attachment_path(data->run_path, attachment); + if (!path) { + return; + } + data->client->RemoveAttachment( + base::FilePath(SENTRY_PATH_PLATFORM_STR(path))); + + if (sentry__attachment_get_bytes(attachment, nullptr)) { + if (sentry__path_remove(path) != 0) { + SENTRY_WARNF( + "failed to remove crashpad attachment \"%s\"", path->path); + } + if (sentry_path_t *dir = sentry__path_dir(path)) { + sentry__path_remove(dir); + sentry__path_free(dir); + } + } + sentry__path_free(path); +} +#endif + static int crashpad_backend_startup( sentry_backend_t *backend, const sentry_options_t *options) @@ -1118,12 +1212,38 @@ crashpad_backend_startup( crashpad::TriState::kEnabled); } +#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \ + || defined(SENTRY_PLATFORM_MACOS) + sentry_scope_observer_t *observer = sentry__scope_observer_new(); + if (observer) { + observer->data = data; + observer->add_attachment = add_attachment; + observer->remove_attachment = remove_attachment; + SENTRY_WITH_SCOPE_MUT_NO_FLUSH (scope) { + if (sentry__scope_add_observer(scope, observer)) { + data->scope_observer = observer; + } + } + } +#endif + return 0; } static void crashpad_backend_shutdown(sentry_backend_t *backend) { + auto *data = static_cast(backend->data); +#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \ + || defined(SENTRY_PLATFORM_MACOS) + if (data->scope_observer) { + SENTRY_WITH_SCOPE_MUT_NO_FLUSH (scope) { + sentry__scope_remove_observer(scope, data->scope_observer); + } + data->scope_observer = nullptr; + } +#endif + #ifdef SENTRY_PLATFORM_LINUX // restore signal handlers to their default state for (const auto signal : g_CrashSignals) { @@ -1133,7 +1253,7 @@ crashpad_backend_shutdown(sentry_backend_t *backend) } #endif - crashpad_state_dtor(static_cast(backend->data)); + crashpad_state_dtor(data); #ifdef SENTRY_PLATFORM_LINUX g_signal_stack.ss_flags = SS_DISABLE; @@ -1304,101 +1424,6 @@ crashpad_backend_prune_database(sentry_backend_t *backend) crashpad::PruneCrashReportDatabase(data->db, &condition); } -#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \ - || defined(SENTRY_PLATFORM_MACOS) -static sentry_path_t * -make_attachment_path(const sentry_path_t *run_path, sentry_value_t attachment) -{ - if (!sentry__attachment_get_bytes(attachment, nullptr)) { - return sentry__attachment_make_path(attachment); - } - - sentry_uuid_t id = sentry__attachment_get_id(attachment); - const char *filename = sentry__attachment_get_filename(attachment); - if (!run_path || sentry_uuid_is_nil(&id) - || sentry__string_empty(filename)) { - return nullptr; - } - - char uuid[37]; - sentry_uuid_as_string(&id, uuid); - sentry_path_t *dir = sentry__path_join_str(run_path, uuid); - sentry_path_t *path = dir ? sentry__path_join_str(dir, filename) : nullptr; - sentry_path_t *parent = path ? sentry__path_dir(path) : nullptr; - bool valid = parent && sentry__path_eq(parent, dir); - sentry__path_free(parent); - sentry__path_free(dir); - if (!valid) { - sentry__path_free(path); - return nullptr; - } - return path; -} - -static void -crashpad_backend_add_attachment(sentry_backend_t *backend, - sentry_value_t attachment, const sentry_options_t *UNUSED(options)) -{ - auto *data = static_cast(backend->data); - if (!data || !data->client) { - return; - } - - size_t bytes_len = 0; - const char *bytes = sentry__attachment_get_bytes(attachment, &bytes_len); - sentry_path_t *path = make_attachment_path(data->run_path, attachment); - if (!path) { - const char *filename = sentry__attachment_get_filename(attachment); - SENTRY_WARNF("failed to create path for crashpad attachment \"%s\"", - filename ? filename : ""); - return; - } - - if (bytes) { - sentry_path_t *dir = sentry__path_dir(path); - int rv = dir ? sentry__path_create_dir_all(dir) : 1; - sentry__path_free(dir); - if (rv != 0 || sentry__path_write_buffer(path, bytes, bytes_len) != 0) { - SENTRY_WARNF( - "failed to write crashpad attachment \"%s\"", path->path); - sentry__path_remove(path); - sentry__path_free(path); - return; - } - } - data->client->AddAttachment(base::FilePath(SENTRY_PATH_PLATFORM_STR(path))); - sentry__path_free(path); -} - -static void -crashpad_backend_remove_attachment( - sentry_backend_t *backend, sentry_value_t attachment) -{ - auto *data = static_cast(backend->data); - if (!data || !data->client) { - return; - } - sentry_path_t *path = make_attachment_path(data->run_path, attachment); - if (!path) { - return; - } - data->client->RemoveAttachment( - base::FilePath(SENTRY_PATH_PLATFORM_STR(path))); - - if (sentry__attachment_get_bytes(attachment, nullptr)) { - if (sentry__path_remove(path) != 0) { - SENTRY_WARNF( - "failed to remove crashpad attachment \"%s\"", path->path); - } - if (sentry_path_t *dir = sentry__path_dir(path)) { - sentry__path_remove(dir); - sentry__path_free(dir); - } - } - sentry__path_free(path); -} -#endif - void sentry__backend_preload(void) { @@ -1430,11 +1455,6 @@ sentry__backend_new(void) backend->get_last_crash_func = crashpad_backend_last_crash; backend->process_old_run_func = crashpad_backend_process_old_run; backend->prune_database_func = crashpad_backend_prune_database; -#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \ - || defined(SENTRY_PLATFORM_MACOS) - backend->add_attachment_func = crashpad_backend_add_attachment; - backend->remove_attachment_func = crashpad_backend_remove_attachment; -#endif backend->data = data; backend->can_capture_after_shutdown = true; diff --git a/src/backends/sentry_backend_native.c b/src/backends/sentry_backend_native.c index 7db9f5489c..974c66b0ea 100644 --- a/src/backends/sentry_backend_native.c +++ b/src/backends/sentry_backend_native.c @@ -205,20 +205,21 @@ wer_register_module(uint64_t app_tid, const sentry_options_t *options) typedef struct { sentry_crash_ipc_t *ipc; pid_t daemon_pid; + sentry_path_t *run_path; sentry_path_t *event_path; sentry_path_t *breadcrumb1_path; sentry_path_t *breadcrumb2_path; sentry_path_t *envelope_path; size_t num_breadcrumbs; volatile long crashed; + sentry_scope_observer_t *scope_observer; } native_backend_state_t; static void native_backend_flush_scope( sentry_backend_t *backend, const sentry_options_t *options); static void native_backend_add_breadcrumb(sentry_backend_t *backend, sentry_value_t breadcrumb, const sentry_options_t *options); -static void native_backend_add_attachment(sentry_backend_t *backend, - sentry_value_t attachment, const sentry_options_t *options); +static void add_attachment(void *data, sentry_value_t attachment); static void native_backend_preload_scope( @@ -229,8 +230,8 @@ native_backend_preload_scope( sentry_value_t attachments = sentry__scope_load_attachments(scope); size_t attachment_count = sentry_value_get_length(attachments); for (size_t i = 0; i < attachment_count; i++) { - native_backend_add_attachment( - backend, sentry_value_get_by_index(attachments, i), options); + add_attachment( + backend->data, sentry_value_get_by_index(attachments, i)); } sentry_value_decref(attachments); breadcrumbs = sentry__scope_breadcrumbs_to_list(scope); @@ -244,6 +245,76 @@ native_backend_preload_scope( sentry_value_decref(breadcrumbs); } +/** + * Creates an attachment path, deriving a unique path in the run directory for + * buffer attachments. + */ +static sentry_path_t * +make_attachment_path(const sentry_path_t *run_path, sentry_value_t attachment) +{ + if (!sentry__attachment_get_bytes(attachment, NULL)) { + return sentry__attachment_make_path(attachment); + } + + sentry_uuid_t id = sentry__attachment_get_id(attachment); + const char *filename = sentry__attachment_get_filename(attachment); + if (!run_path || sentry_uuid_is_nil(&id) + || sentry__string_empty(filename)) { + return NULL; + } + + char uuid[37]; + sentry_uuid_as_string(&id, uuid); + sentry_path_t *dir = sentry__path_join_str(run_path, uuid); + sentry_path_t *path = dir ? sentry__path_join_str(dir, filename) : NULL; + sentry_path_t *parent = path ? sentry__path_dir(path) : NULL; + bool valid = parent && sentry__path_eq(parent, dir); + sentry__path_free(parent); + sentry__path_free(dir); + if (!valid) { + sentry__path_free(path); + return NULL; + } + return path; +} + +static void +add_attachment(void *data, sentry_value_t attachment) +{ + native_backend_state_t *state = (native_backend_state_t *)data; + if (!state) { + return; + } + + // For buffer attachments, derive a path in the run directory and write to + // disk + size_t bytes_len = 0; + const char *bytes = sentry__attachment_get_bytes(attachment, &bytes_len); + if (bytes) { + sentry_path_t *path = make_attachment_path(state->run_path, attachment); + if (!path) { + const char *filename = sentry__attachment_get_filename(attachment); + SENTRY_WARNF("failed to create path for native backend attachment " + "\"%s\"", + filename ? filename : ""); + return; + } + sentry_path_t *dir = sentry__path_dir(path); + int rv = dir ? sentry__path_create_dir_all(dir) : 1; + sentry__path_free(dir); + // Write buffer to disk + if (rv != 0 || sentry__path_write_buffer(path, bytes, bytes_len) != 0) { + SENTRY_WARNF( + "failed to write native backend attachment \"%s\"", path->path); + sentry__path_remove(path); + } + sentry__path_free(path); + } + // For file attachments, the path is already set and points to the actual + // file. The crash daemon will read these files from their original + // locations. +} + static bool native_backend_process_old_run(sentry_backend_t *backend, const sentry_options_t *options, const sentry_path_t *run_path) @@ -624,6 +695,7 @@ native_backend_startup( return 1; } backend->data = state; + state->run_path = sentry__path_clone(options->run->run_path); // Initialize IPC (protected by global synchronization for concurrent // access) @@ -638,6 +710,7 @@ native_backend_startup( #endif if (!state->ipc) { SENTRY_WARN("failed to initialize crash IPC"); + sentry__path_free(state->run_path); sentry_free(state); backend->data = NULL; return 1; @@ -652,6 +725,7 @@ native_backend_startup( SENTRY_WARNF("failed to acquire mutex for context setup: %lu", GetLastError()); sentry__crash_ipc_free(state->ipc); + sentry__path_free(state->run_path); sentry_free(state); backend->data = NULL; return 1; @@ -664,6 +738,7 @@ native_backend_startup( SENTRY_WARNF("failed to acquire semaphore for context setup: %s", strerror(errno)); sentry__crash_ipc_free(state->ipc); + sentry__path_free(state->run_path); sentry_free(state); backend->data = NULL; return 1; @@ -852,6 +927,7 @@ native_backend_startup( < 0) { SENTRY_WARN("failed to initialize crash handler"); sentry__crash_ipc_free(state->ipc); + sentry__path_free(state->run_path); sentry_free(state); backend->data = NULL; return 1; @@ -885,6 +961,7 @@ native_backend_startup( # endif SENTRY_WARN("failed to start crash daemon"); sentry__crash_ipc_free(state->ipc); + sentry__path_free(state->run_path); sentry_free(state); backend->data = NULL; return 1; @@ -954,6 +1031,7 @@ native_backend_startup( } # endif sentry__crash_ipc_free(state->ipc); + sentry__path_free(state->run_path); sentry_free(state); backend->data = NULL; return 1; @@ -961,6 +1039,16 @@ native_backend_startup( #endif SENTRY_DEBUG("native backend started successfully"); + sentry_scope_observer_t *observer = sentry__scope_observer_new(); + if (observer) { + observer->data = state; + observer->add_attachment = add_attachment; + SENTRY_WITH_SCOPE_MUT_NO_FLUSH (scope) { + if (sentry__scope_add_observer(scope, observer)) { + state->scope_observer = observer; + } + } + } return 0; } @@ -974,6 +1062,13 @@ native_backend_shutdown(sentry_backend_t *backend) return; } + if (state->scope_observer) { + SENTRY_WITH_SCOPE_MUT_NO_FLUSH (scope) { + sentry__scope_remove_observer(scope, state->scope_observer); + } + state->scope_observer = NULL; + } + #if defined(SENTRY_PLATFORM_WINDOWS) && !defined(SENTRY_PLATFORM_XBOX) wer_unregister_module(); #endif @@ -1100,43 +1195,11 @@ native_backend_free(sentry_backend_t *backend) sentry__path_free(state->breadcrumb1_path); sentry__path_free(state->breadcrumb2_path); sentry__path_free(state->envelope_path); + sentry__path_free(state->run_path); sentry_free(state); } -/** - * Creates an attachment path, deriving a unique path in the run directory for - * buffer attachments. - */ -static sentry_path_t * -make_attachment_path(const sentry_path_t *run_path, sentry_value_t attachment) -{ - if (!sentry__attachment_get_bytes(attachment, NULL)) { - return sentry__attachment_make_path(attachment); - } - - sentry_uuid_t id = sentry__attachment_get_id(attachment); - const char *filename = sentry__attachment_get_filename(attachment); - if (!run_path || sentry_uuid_is_nil(&id) - || sentry__string_empty(filename)) { - return NULL; - } - - char uuid[37]; - sentry_uuid_as_string(&id, uuid); - sentry_path_t *dir = sentry__path_join_str(run_path, uuid); - sentry_path_t *path = dir ? sentry__path_join_str(dir, filename) : NULL; - sentry_path_t *parent = path ? sentry__path_dir(path) : NULL; - bool valid = parent && sentry__path_eq(parent, dir); - sentry__path_free(parent); - sentry__path_free(dir); - if (!valid) { - sentry__path_free(path); - return NULL; - } - return path; -} - // Writes the scope's attachment list to /__sentry-attachments so the // crash daemon can locate and append them to the crash envelope. static void @@ -1333,42 +1396,6 @@ native_backend_add_breadcrumb(sentry_backend_t *backend, } } -static void -native_backend_add_attachment(sentry_backend_t *backend, - sentry_value_t attachment, const sentry_options_t *options) -{ - (void)backend; // Unused - - // For buffer attachments, derive a path in the run directory and write to - // disk - size_t bytes_len = 0; - const char *bytes = sentry__attachment_get_bytes(attachment, &bytes_len); - if (bytes) { - sentry_path_t *path - = make_attachment_path(options->run->run_path, attachment); - if (!path) { - const char *filename = sentry__attachment_get_filename(attachment); - SENTRY_WARNF("failed to create path for native backend attachment " - "\"%s\"", - filename ? filename : ""); - return; - } - sentry_path_t *dir = sentry__path_dir(path); - int rv = dir ? sentry__path_create_dir_all(dir) : 1; - sentry__path_free(dir); - // Write buffer to disk - if (rv != 0 || sentry__path_write_buffer(path, bytes, bytes_len) != 0) { - SENTRY_WARNF( - "failed to write native backend attachment \"%s\"", path->path); - sentry__path_remove(path); - } - sentry__path_free(path); - } - // For file attachments, the path is already set and points to the actual - // file. The crash daemon will read these files from their original - // locations. -} - /** * Handle exception - called from signal handler via sentry_handle_exception * This processes the event with on_crash/before_send hooks and ends the session @@ -1541,7 +1568,6 @@ sentry__backend_new(void) backend->except_func = native_backend_except; backend->flush_scope_func = native_backend_flush_scope; backend->add_breadcrumb_func = native_backend_add_breadcrumb; - backend->add_attachment_func = native_backend_add_attachment; backend->user_consent_changed_func = native_backend_user_consent_changed; backend->process_old_run_func = native_backend_process_old_run; backend->can_capture_after_shutdown = false; diff --git a/src/sentry_backend.h b/src/sentry_backend.h index 7eec78d3de..c1e54288ad 100644 --- a/src/sentry_backend.h +++ b/src/sentry_backend.h @@ -29,9 +29,6 @@ struct sentry_backend_s { bool (*process_old_run_func)(sentry_backend_t *, const sentry_options_t *options, const sentry_path_t *run_path); void (*prune_database_func)(sentry_backend_t *); - void (*add_attachment_func)( - sentry_backend_t *, sentry_value_t, const sentry_options_t *options); - void (*remove_attachment_func)(sentry_backend_t *, sentry_value_t); void *data; // Whether this backend still runs after shutdown_func was called. bool can_capture_after_shutdown; diff --git a/src/sentry_core.c b/src/sentry_core.c index 9e8cb50455..b178b043d1 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -2107,18 +2107,7 @@ sentry_add_attachment(sentry_value_t attachment) sentry_value_t added = sentry_value_new_null(); SENTRY_WITH_SCOPE_MUT (scope) { - sentry_value_t attachments = sentry__scope_load_attachments(scope); - added = sentry__attachments_find(attachments, attachment); - if (sentry_value_is_null(added)) { - if (options->backend && options->backend->add_attachment_func) { - options->backend->add_attachment_func( - options->backend, attachment, options); - } - added = sentry__scope_add_attachment(scope, attachment); - } else { - sentry_value_decref(attachment); - } - sentry_value_decref(attachments); + added = sentry__scope_add_attachment(scope, attachment); } sentry_options_free((sentry_options_t *)options); sentry_uuid_t uuid = sentry__attachment_get_id(added); @@ -2163,11 +2152,6 @@ sentry_clear_attachments(void) for (size_t i = 0; i < len; i++) { sentry_value_t attachment = sentry_value_get_by_index(attachments, i); - if (options->backend - && options->backend->remove_attachment_func) { - options->backend->remove_attachment_func( - options->backend, attachment); - } SENTRY_SCOPE_NOTIFY(scope, remove_attachment, attachment); } sentry_value_decref(attachments); @@ -2182,22 +2166,8 @@ sentry_remove_attachment(sentry_uuid_t attachment_id) return; } - SENTRY_WITH_OPTIONS (options) { - SENTRY_WITH_SCOPE_MUT (scope) { - sentry_value_t attachments = sentry__scope_load_attachments(scope); - sentry_value_t removed - = sentry__attachments_remove(attachments, &attachment_id); - if (!sentry_value_is_null(removed)) { - if (options->backend - && options->backend->remove_attachment_func) { - options->backend->remove_attachment_func( - options->backend, removed); - } - SENTRY_SCOPE_NOTIFY(scope, remove_attachment, removed); - } - sentry_value_decref(removed); - sentry_value_decref(attachments); - } + SENTRY_WITH_SCOPE_MUT (scope) { + sentry_scope_remove_attachment(scope, attachment_id); } } diff --git a/tests/unit/test_attachments.c b/tests/unit/test_attachments.c index bd75f1b1c2..5240f21338 100644 --- a/tests/unit/test_attachments.c +++ b/tests/unit/test_attachments.c @@ -24,13 +24,11 @@ add_scope_attachments(sentry_envelope_t *envelope) } static void -count_backend_attachment(sentry_backend_t *backend, sentry_value_t attachment, - const sentry_options_t *options) +count_attachment(void *data, sentry_value_t attachment) { - size_t *count = (size_t *)backend->data; + size_t *count = (size_t *)data; (*count)++; - TEST_CHECK(!sentry_value_is_frozen(attachment)); - TEST_CHECK(!!options); + TEST_CHECK(sentry_value_is_frozen(attachment)); } SENTRY_TEST(attachment_placeholder) @@ -146,11 +144,9 @@ SENTRY_TEST(lazy_attachments) SENTRY_TEST(attachments_add_dedupe) { SENTRY_TEST_OPTIONS_NEW(options); - size_t backend_add_count = 0; + size_t add_count = 0; sentry_backend_t *backend = SENTRY_MAKE(sentry_backend_t); TEST_ASSERT(!!backend); - backend->data = &backend_add_count; - backend->add_attachment_func = count_backend_attachment; sentry_options_set_backend(options, backend); sentry_options_add_attachment(options, SENTRY_TEST_PATH_PREFIX ".a.txt"); sentry_options_add_attachment(options, SENTRY_TEST_PATH_PREFIX ".b.txt"); @@ -160,6 +156,14 @@ SENTRY_TEST(attachments_add_dedupe) sentry_init(options); + sentry_scope_observer_t *observer = sentry__scope_observer_new(); + TEST_ASSERT(!!observer); + observer->data = &add_count; + observer->add_attachment = count_attachment; + SENTRY_WITH_SCOPE_MUT_NO_FLUSH (scope) { + TEST_ASSERT(sentry__scope_add_observer(scope, observer)); + } + sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".a.txt"); sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".b.txt"); sentry_attach_file(SENTRY_TEST_PATH_PREFIX ".c.txt"); @@ -168,7 +172,7 @@ SENTRY_TEST(attachments_add_dedupe) sentry_attach_filew(SENTRY_TEST_PATH_PREFIX L".b.txt"); sentry_attach_filew(SENTRY_TEST_PATH_PREFIX L".c.txt"); #endif - TEST_CHECK_INT_EQUAL(backend_add_count, 1); + TEST_CHECK_INT_EQUAL(add_count, 1); sentry_path_t *path_a = sentry__path_from_str(SENTRY_TEST_PATH_PREFIX ".a.txt");